diff options
author | Yang Ni <yangni@google.com> | 2016-11-11 12:30:09 -0800 |
---|---|---|
committer | Yang Ni <yangni@google.com> | 2016-12-06 09:24:52 -0800 |
commit | 75f0d3110b04346b901771f96ce15cdbe907278f (patch) | |
tree | a13ce3211bfb37b0d3088c5f5ff83e247c4167b2 | |
parent | 6babd9ca03e1379380af0c1cfde6f6d3e92ccd29 (diff) | |
download | rs-75f0d3110b04346b901771f96ce15cdbe907278f.tar.gz |
Initial driver for RSoV (RenderScript over Vulkan/SPIR-V)
Bug: 30964317
Supports the following:
* Allocations of 32-bit integers and floating point numbers and vectors
* Single-input single-output kernels
* Co-existence of RSoV scripts and CPU intrinsics
Added default .clang-format for driver code using Google C++ code style.
The RSoV driver is loaded, if and only if the property debug.rs.rsov is
set to non-zero.
Test: RSTest and CTS with debug.rs.rsov set to 0; and RSoVTest with
debug.rs.rsov set to 1.
Change-Id: If63370a502d499e8fc5f4bbd2e90ce84b167c331
36 files changed, 4964 insertions, 8 deletions
diff --git a/rsContext.cpp b/rsContext.cpp index a706a8bc..0c25d04d 100644 --- a/rsContext.cpp +++ b/rsContext.cpp @@ -270,6 +270,12 @@ void * Context::threadProc(void *vrsc) { rsc->mForceCpu = true; } + bool forceRSoV = getProp("debug.rs.rsov") != 0; + if (forceRSoV) { + ALOGD("Force the use of RSoV driver"); + rsc->mForceRSoV = true; + } + bool forceCpu = getProp("debug.rs.default-CPU-driver") != 0; if (forceCpu) { ALOGD("Skipping hardware driver and loading default CPU driver"); @@ -277,7 +283,7 @@ void * Context::threadProc(void *vrsc) { } rsc->mForceCpu |= rsc->mIsGraphicsContext; - rsc->loadDriver(rsc->mForceCpu); + rsc->loadDriver(rsc->mForceCpu, rsc->mForceRSoV); if (!rsc->isSynchronous()) { // Due to legacy we default to normal_graphics diff --git a/rsContext.h b/rsContext.h index fe771ec5..e36eddb7 100644 --- a/rsContext.h +++ b/rsContext.h @@ -312,6 +312,7 @@ protected: int32_t mThreadPriority; bool mIsGraphicsContext; + bool mForceRSoV; bool mForceCpu; RsContextType mContextType; @@ -349,7 +350,10 @@ private: uint32_t runRootScript(); bool loadRuntime(const char* filename); - bool loadDriver(bool forceDefault); + // Loads the driver. + // forceDefault: If true, loads the default CPU driver. + // forceRSoV: If true, overrides forceDefault and loads the RSoV driver. + bool loadDriver(bool forceDefault, bool forceRSoV); static void * threadProc(void *); static void * helperThreadProc(void *); diff --git a/rsDriverLoader.cpp b/rsDriverLoader.cpp index 16efa0d7..9e3c39da 100644 --- a/rsDriverLoader.cpp +++ b/rsDriverLoader.cpp @@ -232,16 +232,27 @@ error: -bool Context::loadDriver(bool forceDefault) { +bool Context::loadDriver(bool forceDefault, bool forceRSoV) { bool loadDefault = true; // Provide a mechanism for dropping in a different RS driver. #ifndef RS_COMPATIBILITY_LIB + + if (forceRSoV) { + // If the debug property is set to use the RSoV driver, load it and fail + // if it does not load. + if (loadRuntime("libRSDriver_RSoV.so")) { + ALOGV("Successfully loaded the RSoV driver!"); + return true; + } + ALOGE("Failed to load the RSoV driver!"); + return false; + } + #ifdef OVERRIDE_RS_DRIVER #define XSTR(S) #S #define STR(S) XSTR(S) #define OVERRIDE_RS_DRIVER_STRING STR(OVERRIDE_RS_DRIVER) - if (!forceDefault) { if (loadRuntime(OVERRIDE_RS_DRIVER_STRING)) { ALOGV("Successfully loaded runtime: %s", OVERRIDE_RS_DRIVER_STRING); diff --git a/rsov/compiler/Android.mk b/rsov/compiler/Android.mk index 7f31d67c..477f1d9d 100644 --- a/rsov/compiler/Android.mk +++ b/rsov/compiler/Android.mk @@ -59,12 +59,9 @@ LOCAL_C_INCLUDES := \ LOCAL_MODULE := rs2spirv LOCAL_MODULE_CLASS := EXECUTABLES -# TODO: handle windows and darwin - -LOCAL_MODULE_HOST_OS := linux LOCAL_IS_HOST_MODULE := true -LOCAL_SHARED_LIBRARIES_linux += libLLVM libbcinfo libSPIRV +LOCAL_SHARED_LIBRARIES += libLLVM libbcinfo libSPIRV # TODO: fix the remaining warnings @@ -132,6 +129,20 @@ include $(BUILD_EXECUTABLE) endif # Don't build in unbundled branches #===================================================================== +# Device executable bcc_rsov +#===================================================================== + +include $(CLEAR_VARS) +include $(CLEAR_TBLGEN_VARS) + +LOCAL_MODULE:= bcc_rsov +LOCAL_MULTILIB := first +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_SRC_FILES := bcc_rsov.sh + +include $(BUILD_PREBUILT) + +#===================================================================== # Include Subdirectories #===================================================================== diff --git a/rsov/compiler/bcc_rsov.sh b/rsov/compiler/bcc_rsov.sh new file mode 100755 index 00000000..c2cb2196 --- /dev/null +++ b/rsov/compiler/bcc_rsov.sh @@ -0,0 +1,65 @@ +#! /system/bin/sh +# +# Copyright 2016, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +function help() { + echo "USAGE: $0 [options] <input>" + echo + echo "OPTIONS:" + echo " -h Show this help message." + echo " -o <file> Write output to file." +} + +OUTPUT_FILE="" + +while getopts "ho:" opt; do + case "$opt" in + h) + help + exit 0 + ;; + o) + OUTPUT_FILE=$OPTARG + ;; + esac +done + +shift $((OPTIND-1)) + +if [[ "$#" -ne 1 ]]; then + help + exit -1 +fi + +INPUT_FILE=$1 + +if [[ -z "$OUTPUT_FILE" ]]; then + OUTPUT_FILE="${INPUT_FILE%.*}.spv" +fi + +KERNEL="${INPUT_FILE%.*}_k.spv" +KERNEL_TXT="${INPUT_FILE%.*}_k.spt" +WRAPPER="${INPUT_FILE%.*}_w.spt" +OUTPUT_TXT="${INPUT_FILE%.*}.spt" + +eval rs2spirv $INPUT_FILE -o $KERNEL -wo $WRAPPER && +eval spirv-dis $KERNEL --no-color -o $KERNEL_TXT && +eval rs2spirv -o $OUTPUT_TXT -lk $KERNEL_TXT -lw $WRAPPER && +eval spirv-as $OUTPUT_TXT -o $OUTPUT_FILE + +#rm -f $INPUT_FILE $KERNEL $KERNEL_TXT $WRAPPER $OUTPUT_TXT + +exit $? diff --git a/rsov/driver/.clang-format b/rsov/driver/.clang-format new file mode 100644 index 00000000..e8b6a2d9 --- /dev/null +++ b/rsov/driver/.clang-format @@ -0,0 +1,95 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: true +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeCategories: + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 8 +UseTab: Never +... + diff --git a/rsov/driver/Android.mk b/rsov/driver/Android.mk new file mode 100644 index 00000000..5309ba8e --- /dev/null +++ b/rsov/driver/Android.mk @@ -0,0 +1,56 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH :=$(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libRSDriver_RSoV + +LOCAL_SRC_FILES := \ + rsovAllocation.cpp \ + rsovContext.cpp \ + rsovCore.cpp \ + rsovElement.cpp \ + rsovRuntimeStubs.cpp \ + rsovSampler.cpp \ + rsovScript.cpp \ + rsovScriptGroup.cpp \ + rsovType.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libRS_internal \ + libRSCpuRef \ + libc++ \ + libcutils \ + libdl \ + liblog \ + libsync \ + libutils \ + libvulkan + +LOCAL_C_INCLUDES := \ + frameworks/native/vulkan/include \ + frameworks/rs \ + frameworks/rs/cpu_ref \ + +LOCAL_C_INCLUDES += \ + +LOCAL_CFLAGS := -Werror -Wall -Wextra -fno-exceptions +# TODO: remove warnings on unused variables and parameters +LOCAL_CFLAGS += -Wno-unused-variable -Wno-unused-parameter + +include $(BUILD_SHARED_LIBRARY) diff --git a/rsov/driver/rsovAllocation.cpp b/rsov/driver/rsovAllocation.cpp new file mode 100644 index 00000000..fdb477d1 --- /dev/null +++ b/rsov/driver/rsovAllocation.cpp @@ -0,0 +1,790 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rsovAllocation.h" + +#include <map> + +#include "rsAllocation.h" +#include "rsContext.h" +#include "rsCppUtils.h" +#include "rsElement.h" +#include "rsType.h" +#include "rsovContext.h" +#include "rsovCore.h" + +namespace android { +namespace renderscript { +namespace rsov { + +namespace { + +using std::make_pair; + +// TODO: handle 8-bit, 16-bit, and 64-bit integers and floating point numbers +const std::map<std::pair<RsDataType, uint32_t>, VkFormat> mapElementToFormat{ + make_pair(make_pair(RS_TYPE_FLOAT_32, 1), VK_FORMAT_R32_SFLOAT), + make_pair(make_pair(RS_TYPE_FLOAT_32, 2), VK_FORMAT_R32G32_SFLOAT), + make_pair(make_pair(RS_TYPE_FLOAT_32, 3), VK_FORMAT_R32G32B32_SFLOAT), + make_pair(make_pair(RS_TYPE_FLOAT_32, 4), VK_FORMAT_R32G32B32A32_SFLOAT), + + make_pair(make_pair(RS_TYPE_SIGNED_32, 1), VK_FORMAT_R32_SINT), + make_pair(make_pair(RS_TYPE_SIGNED_32, 2), VK_FORMAT_R32G32_SINT), + make_pair(make_pair(RS_TYPE_SIGNED_32, 3), VK_FORMAT_R32G32B32_SINT), + make_pair(make_pair(RS_TYPE_SIGNED_32, 4), VK_FORMAT_R32G32B32A32_SINT), + + make_pair(make_pair(RS_TYPE_UNSIGNED_32, 1), VK_FORMAT_R32_UINT), + make_pair(make_pair(RS_TYPE_UNSIGNED_32, 2), VK_FORMAT_R32G32_UINT), + make_pair(make_pair(RS_TYPE_UNSIGNED_32, 3), VK_FORMAT_R32G32B32_UINT), + make_pair(make_pair(RS_TYPE_UNSIGNED_32, 4), VK_FORMAT_R32G32B32A32_UINT), +}; + +VkFormat VkFormatFromRSElement(const Element &elem) { + // TODO: reject struct, allocation, and other non-numeric element + rsAssert(!elem.getFieldCount()); + + RsDataType dataType = elem.getType(); + uint32_t vectorWidth = elem.getVectorSize(); + + auto it = mapElementToFormat.find(make_pair(dataType, vectorWidth)); + if (it != mapElementToFormat.end()) { + return it->second; + } + + rsAssert(0 && "Unexpected RS Element to map to VkFormat"); + + return VK_FORMAT_R32G32B32A32_SFLOAT; +} + +size_t DeriveYUVLayout(int yuv, Allocation::Hal::DrvState *state) { + // For the flexible YCbCr format, layout is initialized during call to + // Allocation::ioReceive. Return early and avoid clobberring any + // pre-existing layout. + if (yuv == HAL_PIXEL_FORMAT_YCbCr_420_888) { + return 0; + } + + // YUV only supports basic 2d + // so we can stash the plane pointers in the mipmap levels. + size_t uvSize = 0; + state->lod[1].dimX = state->lod[0].dimX / 2; + state->lod[1].dimY = state->lod[0].dimY / 2; + state->lod[2].dimX = state->lod[0].dimX / 2; + state->lod[2].dimY = state->lod[0].dimY / 2; + state->yuv.shift = 1; + state->yuv.step = 1; + state->lodCount = 3; + + switch (yuv) { + case HAL_PIXEL_FORMAT_YV12: + state->lod[2].stride = rsRound(state->lod[0].stride >> 1, 16); + state->lod[2].mallocPtr = ((uint8_t *)state->lod[0].mallocPtr) + + (state->lod[0].stride * state->lod[0].dimY); + uvSize += state->lod[2].stride * state->lod[2].dimY; + + state->lod[1].stride = state->lod[2].stride; + state->lod[1].mallocPtr = ((uint8_t *)state->lod[2].mallocPtr) + + (state->lod[2].stride * state->lod[2].dimY); + uvSize += state->lod[1].stride * state->lod[2].dimY; + break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: // NV21 + // state->lod[1].dimX = state->lod[0].dimX; + state->lod[1].stride = state->lod[0].stride; + state->lod[2].stride = state->lod[0].stride; + state->lod[2].mallocPtr = ((uint8_t *)state->lod[0].mallocPtr) + + (state->lod[0].stride * state->lod[0].dimY); + state->lod[1].mallocPtr = ((uint8_t *)state->lod[2].mallocPtr) + 1; + uvSize += state->lod[1].stride * state->lod[1].dimY; + state->yuv.step = 2; + break; + default: + rsAssert(0); + } + + return uvSize; +} + +// TODO: Dedup this with the same code under frameworks/rs/driver +size_t AllocationBuildPointerTable(const Context *rsc, const Allocation *alloc, + const Type *type, uint8_t *ptr, + size_t requiredAlignment) { + alloc->mHal.drvState.lod[0].dimX = type->getDimX(); + alloc->mHal.drvState.lod[0].dimY = type->getDimY(); + alloc->mHal.drvState.lod[0].dimZ = type->getDimZ(); + alloc->mHal.drvState.lod[0].mallocPtr = 0; + // Stride needs to be aligned to a boundary defined by requiredAlignment! + size_t stride = + alloc->mHal.drvState.lod[0].dimX * type->getElementSizeBytes(); + alloc->mHal.drvState.lod[0].stride = rsRound(stride, requiredAlignment); + alloc->mHal.drvState.lodCount = type->getLODCount(); + alloc->mHal.drvState.faceCount = type->getDimFaces(); + + size_t offsets[Allocation::MAX_LOD]; + memset(offsets, 0, sizeof(offsets)); + + size_t o = alloc->mHal.drvState.lod[0].stride * + rsMax(alloc->mHal.drvState.lod[0].dimY, 1u) * + rsMax(alloc->mHal.drvState.lod[0].dimZ, 1u); + if (alloc->mHal.state.yuv) { + o += DeriveYUVLayout(alloc->mHal.state.yuv, &alloc->mHal.drvState); + + for (uint32_t ct = 1; ct < alloc->mHal.drvState.lodCount; ct++) { + offsets[ct] = (size_t)alloc->mHal.drvState.lod[ct].mallocPtr; + } + } else if (alloc->mHal.drvState.lodCount > 1) { + uint32_t tx = alloc->mHal.drvState.lod[0].dimX; + uint32_t ty = alloc->mHal.drvState.lod[0].dimY; + uint32_t tz = alloc->mHal.drvState.lod[0].dimZ; + for (uint32_t lod = 1; lod < alloc->mHal.drvState.lodCount; lod++) { + alloc->mHal.drvState.lod[lod].dimX = tx; + alloc->mHal.drvState.lod[lod].dimY = ty; + alloc->mHal.drvState.lod[lod].dimZ = tz; + alloc->mHal.drvState.lod[lod].stride = + rsRound(tx * type->getElementSizeBytes(), requiredAlignment); + offsets[lod] = o; + o += alloc->mHal.drvState.lod[lod].stride * rsMax(ty, 1u) * rsMax(tz, 1u); + if (tx > 1) tx >>= 1; + if (ty > 1) ty >>= 1; + if (tz > 1) tz >>= 1; + } + } + + alloc->mHal.drvState.faceOffset = o; + + alloc->mHal.drvState.lod[0].mallocPtr = ptr; + for (uint32_t lod = 1; lod < alloc->mHal.drvState.lodCount; lod++) { + alloc->mHal.drvState.lod[lod].mallocPtr = ptr + offsets[lod]; + } + + size_t allocSize = alloc->mHal.drvState.faceOffset; + if (alloc->mHal.drvState.faceCount) { + allocSize *= 6; + } + + return allocSize; +} + +size_t AllocationBuildPointerTable(const Context *rsc, const Allocation *alloc, + const Type *type, uint8_t *ptr) { + return AllocationBuildPointerTable(rsc, alloc, type, ptr, + Allocation::kMinimumRSAlignment); +} + +uint8_t *GetOffsetPtr(const Allocation *alloc, uint32_t xoff, uint32_t yoff, + uint32_t zoff, uint32_t lod, + RsAllocationCubemapFace face) { + uint8_t *ptr = (uint8_t *)alloc->mHal.drvState.lod[lod].mallocPtr; + ptr += face * alloc->mHal.drvState.faceOffset; + ptr += zoff * alloc->mHal.drvState.lod[lod].dimY * + alloc->mHal.drvState.lod[lod].stride; + ptr += yoff * alloc->mHal.drvState.lod[lod].stride; + ptr += xoff * alloc->mHal.state.elementSizeBytes; + return ptr; +} + +void mip565(const Allocation *alloc, int lod, RsAllocationCubemapFace face) { + uint32_t w = alloc->mHal.drvState.lod[lod + 1].dimX; + uint32_t h = alloc->mHal.drvState.lod[lod + 1].dimY; + + for (uint32_t y = 0; y < h; y++) { + uint16_t *oPtr = (uint16_t *)GetOffsetPtr(alloc, 0, y, 0, lod + 1, face); + const uint16_t *i1 = + (uint16_t *)GetOffsetPtr(alloc, 0, 0, y * 2, lod, face); + const uint16_t *i2 = + (uint16_t *)GetOffsetPtr(alloc, 0, 0, y * 2 + 1, lod, face); + + for (uint32_t x = 0; x < w; x++) { + *oPtr = rsBoxFilter565(i1[0], i1[1], i2[0], i2[1]); + oPtr++; + i1 += 2; + i2 += 2; + } + } +} + +void mip8888(const Allocation *alloc, int lod, RsAllocationCubemapFace face) { + uint32_t w = alloc->mHal.drvState.lod[lod + 1].dimX; + uint32_t h = alloc->mHal.drvState.lod[lod + 1].dimY; + + for (uint32_t y = 0; y < h; y++) { + uint32_t *oPtr = (uint32_t *)GetOffsetPtr(alloc, 0, y, 0, lod + 1, face); + const uint32_t *i1 = + (uint32_t *)GetOffsetPtr(alloc, 0, y * 2, 0, lod, face); + const uint32_t *i2 = + (uint32_t *)GetOffsetPtr(alloc, 0, y * 2 + 1, 0, lod, face); + + for (uint32_t x = 0; x < w; x++) { + *oPtr = rsBoxFilter8888(i1[0], i1[1], i2[0], i2[1]); + oPtr++; + i1 += 2; + i2 += 2; + } + } +} + +void mip8(const Allocation *alloc, int lod, RsAllocationCubemapFace face) { + uint32_t w = alloc->mHal.drvState.lod[lod + 1].dimX; + uint32_t h = alloc->mHal.drvState.lod[lod + 1].dimY; + + for (uint32_t y = 0; y < h; y++) { + uint8_t *oPtr = GetOffsetPtr(alloc, 0, y, 0, lod + 1, face); + const uint8_t *i1 = GetOffsetPtr(alloc, 0, y * 2, 0, lod, face); + const uint8_t *i2 = GetOffsetPtr(alloc, 0, y * 2 + 1, 0, lod, face); + + for (uint32_t x = 0; x < w; x++) { + *oPtr = (uint8_t)(((uint32_t)i1[0] + i1[1] + i2[0] + i2[1]) * 0.25f); + oPtr++; + i1 += 2; + i2 += 2; + } + } +} + +} // anonymous namespace + +RSoVAllocation::RSoVAllocation(RSoVContext *context, const Type *type) + : mRSoV(context), + mDevice(context->getDevice()), + mType(type), + mWidth(type->getDimX()), + mHeight(type->getDimY()), + mDepth(type->getDimZ()) { + InitImage(); +} + +RSoVAllocation::~RSoVAllocation() { + vkDestroyImageView(mDevice, mImageView, nullptr); + vkDestroyImage(mDevice, mImage, nullptr); + vkFreeMemory(mDevice, mMem, nullptr); +} + +void RSoVAllocation::InitImage() { + VkResult res; + + mFormat = VkFormatFromRSElement(*mType->getElement()); + + const uint32_t width = mWidth; + const uint32_t height = mHeight; + const uint32_t depth = mDepth; + + VkImageType imageType = + depth > 0 ? VK_IMAGE_TYPE_3D + : (height > 0 ? VK_IMAGE_TYPE_2D : VK_IMAGE_TYPE_1D); + + VkImageCreateInfo createInfo = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .imageType = imageType, + .format = mFormat, + .extent = {width, rsMax(height, 1U), rsMax(depth, 1U)}, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_LINEAR, + .usage = VK_IMAGE_USAGE_STORAGE_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED, + }; + + res = vkCreateImage(mDevice, &createInfo, nullptr, &mImage); + rsAssert(res == VK_SUCCESS); + + VkMemoryRequirements mem_reqs; + vkGetImageMemoryRequirements(mDevice, mImage, &mem_reqs); + + ALOGI("size of memory needed = %u", (uint)mem_reqs.size); + + VkMemoryAllocateInfo allocateInfo = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = nullptr, + .allocationSize = mem_reqs.size, + }; + + /* Use the memory properties to determine the type of memory required */ + bool pass; + pass = mRSoV->MemoryTypeFromProperties( + mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &allocateInfo.memoryTypeIndex); + ALOGI("TypeBits = 0x%08X", mem_reqs.memoryTypeBits); + rsAssert(pass); + + // TODO: Make this aligned + res = vkAllocateMemory(mDevice, &allocateInfo, nullptr, &mMem); + rsAssert(res == VK_SUCCESS); + + res = vkBindImageMemory(mDevice, mImage, mMem, 0); + rsAssert(res == VK_SUCCESS); + + VkImageViewType viewType = + depth > 0 ? VK_IMAGE_VIEW_TYPE_3D + : (height > 0 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_1D); + + VkImageViewCreateInfo view_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .pNext = nullptr, + .image = mImage, + .viewType = viewType, + .format = mFormat, + .components = + { + .r = VK_COMPONENT_SWIZZLE_IDENTITY, + .g = VK_COMPONENT_SWIZZLE_IDENTITY, + .b = VK_COMPONENT_SWIZZLE_IDENTITY, + .a = VK_COMPONENT_SWIZZLE_IDENTITY, + }, + .subresourceRange = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + + res = vkCreateImageView(mDevice, &view_info, nullptr, &mImageView); + rsAssert(res == VK_SUCCESS); + + mImageLayout = VK_IMAGE_LAYOUT_GENERAL; + + mImageInfo = { + .imageView = mImageView, .imageLayout = mImageLayout, + }; + + res = vkMapMemory(mDevice, mMem, 0, mem_reqs.size, 0, (void **)&mPtr); + rsAssert(res == VK_SUCCESS); +} + +} // namespace rsov +} // namespace renderscript +} // namespace android + +using android::renderscript::Allocation; +using android::renderscript::Context; +using android::renderscript::Element; +using android::renderscript::Type; +using android::renderscript::rs_allocation; +using android::renderscript::rsMax; +using namespace android::renderscript::rsov; + +bool rsovAllocationInit(const Context *rsc, Allocation *alloc, bool forceZero) { + RSoVHal *hal = static_cast<RSoVHal *>(rsc->mHal.drv); + RSoVContext *rsov = hal->mRSoV; + const Type *type = alloc->getType(); + + RSoVAllocation *rsovAlloc = new RSoVAllocation(rsov, type); + alloc->mHal.drv = rsovAlloc; + AllocationBuildPointerTable(rsc, alloc, type, + (uint8_t *)rsovAlloc->getHostPtr()); + return true; +} + +void rsovAllocationDestroy(const Context *rsc, Allocation *alloc) { + RSoVAllocation *rsovAlloc = static_cast<RSoVAllocation *>(alloc->mHal.drv); + delete rsovAlloc; + alloc->mHal.drv = nullptr; +} + +void rsovAllocationData1D(const Context *rsc, const Allocation *alloc, + uint32_t xoff, uint32_t lod, size_t count, + const void *data, size_t sizeBytes) { + const size_t eSize = alloc->mHal.state.type->getElementSizeBytes(); + uint8_t *ptr = + GetOffsetPtr(alloc, xoff, 0, 0, 0, RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X); + size_t size = count * eSize; + if (ptr != data) { + // Skip the copy if we are the same allocation. This can arise from + // our Bitmap optimization, where we share the same storage. + if (alloc->mHal.state.hasReferences) { + alloc->incRefs(data, count); + alloc->decRefs(ptr, count); + } + memcpy(ptr, data, size); + } +} + +void rsovAllocationData2D(const Context *rsc, const Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t lod, + RsAllocationCubemapFace face, uint32_t w, uint32_t h, + const void *data, size_t sizeBytes, size_t stride) { + size_t eSize = alloc->mHal.state.elementSizeBytes; + size_t lineSize = eSize * w; + if (!stride) { + stride = lineSize; + } + + if (alloc->mHal.drvState.lod[0].mallocPtr) { + const uint8_t *src = static_cast<const uint8_t *>(data); + uint8_t *dst = GetOffsetPtr(alloc, xoff, yoff, 0, lod, face); + + for (uint32_t line = yoff; line < (yoff + h); line++) { + if (alloc->mHal.state.hasReferences) { + alloc->incRefs(src, w); + alloc->decRefs(dst, w); + } + memcpy(dst, src, lineSize); + src += stride; + dst += alloc->mHal.drvState.lod[lod].stride; + } + // TODO: handle YUV Allocations + if (alloc->mHal.state.yuv) { + size_t clineSize = lineSize; + int lod = 1; + int maxLod = 2; + if (alloc->mHal.state.yuv == HAL_PIXEL_FORMAT_YV12) { + maxLod = 3; + clineSize >>= 1; + } else if (alloc->mHal.state.yuv == HAL_PIXEL_FORMAT_YCrCb_420_SP) { + lod = 2; + maxLod = 3; + } + + while (lod < maxLod) { + uint8_t *dst = GetOffsetPtr(alloc, xoff, yoff, 0, lod, face); + + for (uint32_t line = (yoff >> 1); line < ((yoff + h) >> 1); line++) { + memcpy(dst, src, clineSize); + // When copying from an array to an Allocation, the src pointer + // to the array should just move by the number of bytes copied. + src += clineSize; + dst += alloc->mHal.drvState.lod[lod].stride; + } + lod++; + } + } + } +} + +void rsovAllocationData3D(const Context *rsc, const Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t zoff, + uint32_t lod, uint32_t w, uint32_t h, uint32_t d, + const void *data, size_t sizeBytes, size_t stride) { + uint32_t eSize = alloc->mHal.state.elementSizeBytes; + uint32_t lineSize = eSize * w; + if (!stride) { + stride = lineSize; + } + + if (alloc->mHal.drvState.lod[0].mallocPtr) { + const uint8_t *src = static_cast<const uint8_t *>(data); + for (uint32_t z = zoff; z < (d + zoff); z++) { + uint8_t *dst = GetOffsetPtr(alloc, xoff, yoff, z, lod, + RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X); + for (uint32_t line = yoff; line < (yoff + h); line++) { + if (alloc->mHal.state.hasReferences) { + alloc->incRefs(src, w); + alloc->decRefs(dst, w); + } + memcpy(dst, src, lineSize); + src += stride; + dst += alloc->mHal.drvState.lod[lod].stride; + } + } + } +} + +void rsovAllocationRead1D(const Context *rsc, const Allocation *alloc, + uint32_t xoff, uint32_t lod, size_t count, void *data, + size_t sizeBytes) { + const size_t eSize = alloc->mHal.state.type->getElementSizeBytes(); + const uint8_t *ptr = + GetOffsetPtr(alloc, xoff, 0, 0, 0, RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X); + if (data != ptr) { + // Skip the copy if we are the same allocation. This can arise from + // our Bitmap optimization, where we share the same storage. + memcpy(data, ptr, count * eSize); + } +} + +void rsovAllocationRead2D(const Context *rsc, const Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t lod, + RsAllocationCubemapFace face, uint32_t w, uint32_t h, + void *data, size_t sizeBytes, size_t stride) { + size_t eSize = alloc->mHal.state.elementSizeBytes; + size_t lineSize = eSize * w; + if (!stride) { + stride = lineSize; + } + + if (alloc->mHal.drvState.lod[0].mallocPtr) { + uint8_t *dst = static_cast<uint8_t *>(data); + const uint8_t *src = GetOffsetPtr(alloc, xoff, yoff, 0, lod, face); + if (dst == src) { + // Skip the copy if we are the same allocation. This can arise from + // our Bitmap optimization, where we share the same storage. + return; + } + + for (uint32_t line = yoff; line < (yoff + h); line++) { + memcpy(dst, src, lineSize); + dst += stride; + src += alloc->mHal.drvState.lod[lod].stride; + } + } else { + ALOGE("Add code to readback from non-script memory"); + } +} + +void rsovAllocationRead3D(const Context *rsc, const Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t zoff, + uint32_t lod, uint32_t w, uint32_t h, uint32_t d, + void *data, size_t sizeBytes, size_t stride) { + uint32_t eSize = alloc->mHal.state.elementSizeBytes; + uint32_t lineSize = eSize * w; + if (!stride) { + stride = lineSize; + } + + if (alloc->mHal.drvState.lod[0].mallocPtr) { + uint8_t *dst = static_cast<uint8_t *>(data); + for (uint32_t z = zoff; z < (d + zoff); z++) { + const uint8_t *src = GetOffsetPtr(alloc, xoff, yoff, z, lod, + RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X); + if (dst == src) { + // Skip the copy if we are the same allocation. This can arise from + // our Bitmap optimization, where we share the same storage. + return; + } + + for (uint32_t line = yoff; line < (yoff + h); line++) { + memcpy(dst, src, lineSize); + dst += stride; + src += alloc->mHal.drvState.lod[lod].stride; + } + } + } +} + +void *rsovAllocationLock1D(const Context *rsc, const Allocation *alloc) { + return alloc->mHal.drvState.lod[0].mallocPtr; +} + +void rsovAllocationUnlock1D(const Context *rsc, const Allocation *alloc) {} + +void rsovAllocationData1D_alloc(const Context *rsc, const Allocation *dstAlloc, + uint32_t dstXoff, uint32_t dstLod, size_t count, + const Allocation *srcAlloc, uint32_t srcXoff, + uint32_t srcLod) {} + +void rsovAllocationData2D_alloc_script( + const Context *rsc, const Allocation *dstAlloc, uint32_t dstXoff, + uint32_t dstYoff, uint32_t dstLod, RsAllocationCubemapFace dstFace, + uint32_t w, uint32_t h, const Allocation *srcAlloc, uint32_t srcXoff, + uint32_t srcYoff, uint32_t srcLod, RsAllocationCubemapFace srcFace) { + size_t elementSize = dstAlloc->getType()->getElementSizeBytes(); + for (uint32_t i = 0; i < h; i++) { + uint8_t *dstPtr = + GetOffsetPtr(dstAlloc, dstXoff, dstYoff + i, 0, dstLod, dstFace); + uint8_t *srcPtr = + GetOffsetPtr(srcAlloc, srcXoff, srcYoff + i, 0, srcLod, srcFace); + memcpy(dstPtr, srcPtr, w * elementSize); + } +} + +void rsovAllocationData3D_alloc_script( + const Context *rsc, const Allocation *dstAlloc, uint32_t dstXoff, + uint32_t dstYoff, uint32_t dstZoff, uint32_t dstLod, uint32_t w, uint32_t h, + uint32_t d, const Allocation *srcAlloc, uint32_t srcXoff, uint32_t srcYoff, + uint32_t srcZoff, uint32_t srcLod) { + uint32_t elementSize = dstAlloc->getType()->getElementSizeBytes(); + for (uint32_t j = 0; j < d; j++) { + for (uint32_t i = 0; i < h; i++) { + uint8_t *dstPtr = + GetOffsetPtr(dstAlloc, dstXoff, dstYoff + i, dstZoff + j, dstLod, + RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X); + uint8_t *srcPtr = + GetOffsetPtr(srcAlloc, srcXoff, srcYoff + i, srcZoff + j, srcLod, + RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X); + memcpy(dstPtr, srcPtr, w * elementSize); + } + } +} + +void rsovAllocationData2D_alloc( + const Context *rsc, const Allocation *dstAlloc, uint32_t dstXoff, + uint32_t dstYoff, uint32_t dstLod, RsAllocationCubemapFace dstFace, + uint32_t w, uint32_t h, const Allocation *srcAlloc, uint32_t srcXoff, + uint32_t srcYoff, uint32_t srcLod, RsAllocationCubemapFace srcFace) { + if (!dstAlloc->getIsScript() && !srcAlloc->getIsScript()) { + rsc->setError(RS_ERROR_FATAL_DRIVER, + "Non-script allocation copies not " + "yet implemented."); + return; + } + rsovAllocationData2D_alloc_script(rsc, dstAlloc, dstXoff, dstYoff, dstLod, + dstFace, w, h, srcAlloc, srcXoff, srcYoff, + srcLod, srcFace); +} + +void rsovAllocationData3D_alloc(const Context *rsc, const Allocation *dstAlloc, + uint32_t dstXoff, uint32_t dstYoff, + uint32_t dstZoff, uint32_t dstLod, uint32_t w, + uint32_t h, uint32_t d, + const Allocation *srcAlloc, uint32_t srcXoff, + uint32_t srcYoff, uint32_t srcZoff, + uint32_t srcLod) { + if (!dstAlloc->getIsScript() && !srcAlloc->getIsScript()) { + rsc->setError(RS_ERROR_FATAL_DRIVER, + "Non-script allocation copies not " + "yet implemented."); + return; + } + rsovAllocationData3D_alloc_script(rsc, dstAlloc, dstXoff, dstYoff, dstZoff, + dstLod, w, h, d, srcAlloc, srcXoff, srcYoff, + srcZoff, srcLod); +} + +void rsovAllocationAdapterOffset(const Context *rsc, const Allocation *alloc) { + // Get a base pointer to the new LOD + const Allocation *base = alloc->mHal.state.baseAlloc; + const Type *type = alloc->mHal.state.type; + if (base == nullptr) { + return; + } + + const int lodBias = alloc->mHal.state.originLOD; + uint32_t lodCount = rsMax(alloc->mHal.drvState.lodCount, (uint32_t)1); + for (uint32_t lod = 0; lod < lodCount; lod++) { + alloc->mHal.drvState.lod[lod] = base->mHal.drvState.lod[lod + lodBias]; + alloc->mHal.drvState.lod[lod].mallocPtr = GetOffsetPtr( + alloc, alloc->mHal.state.originX, alloc->mHal.state.originY, + alloc->mHal.state.originZ, lodBias, + (RsAllocationCubemapFace)alloc->mHal.state.originFace); + } +} + +bool rsovAllocationAdapterInit(const Context *rsc, Allocation *alloc) { +// TODO: may need a RSoV Allocation here +#if 0 + DrvAllocation *drv = (DrvAllocation *)calloc(1, sizeof(DrvAllocation)); + if (!drv) { + return false; + } + alloc->mHal.drv = drv; +#endif + // We need to build an allocation that looks like a subset of the parent + // allocation + rsovAllocationAdapterOffset(rsc, alloc); + + return true; +} + +void rsovAllocationSyncAll(const Context *rsc, const Allocation *alloc, + RsAllocationUsageType src) { + // TODO: anything to do here? +} + +void rsovAllocationMarkDirty(const Context *rsc, const Allocation *alloc) { + // TODO: anything to do here? +} + +void rsovAllocationResize(const Context *rsc, const Allocation *alloc, + const Type *newType, bool zeroNew) { + // TODO: implement this + // can this be done without copying, if the new size is greater than the + // original? +} + +void rsovAllocationGenerateMipmaps(const Context *rsc, + const Allocation *alloc) { + if (!alloc->mHal.drvState.lod[0].mallocPtr) { + return; + } + uint32_t numFaces = alloc->getType()->getDimFaces() ? 6 : 1; + for (uint32_t face = 0; face < numFaces; face++) { + for (uint32_t lod = 0; lod < (alloc->getType()->getLODCount() - 1); lod++) { + switch (alloc->getType()->getElement()->getSizeBits()) { + case 32: + mip8888(alloc, lod, (RsAllocationCubemapFace)face); + break; + case 16: + mip565(alloc, lod, (RsAllocationCubemapFace)face); + break; + case 8: + mip8(alloc, lod, (RsAllocationCubemapFace)face); + break; + } + } + } +} + +uint32_t rsovAllocationGrallocBits(const Context *rsc, Allocation *alloc) { + return 0; +} + +void rsovAllocationUpdateCachedObject(const Context *rsc, + const Allocation *alloc, + rs_allocation *obj) { + obj->p = alloc; +#ifdef __LP64__ + if (alloc != nullptr) { + obj->r = alloc->mHal.drvState.lod[0].mallocPtr; + obj->v1 = alloc->mHal.drv; + obj->v2 = (void *)alloc->mHal.drvState.lod[0].stride; + } else { + obj->r = nullptr; + obj->v1 = nullptr; + obj->v2 = nullptr; + } +#endif +} + +void rsovAllocationSetSurface(const Context *rsc, Allocation *alloc, + ANativeWindow *nw) { + // TODO: implement this +} + +void rsovAllocationIoSend(const Context *rsc, Allocation *alloc) { + // TODO: implement this +} + +void rsovAllocationIoReceive(const Context *rsc, Allocation *alloc) { + // TODO: implement this +} + +void rsovAllocationElementData(const Context *rsc, const Allocation *alloc, + uint32_t x, uint32_t y, uint32_t z, + const void *data, uint32_t cIdx, + size_t sizeBytes) { + uint8_t *ptr = + GetOffsetPtr(alloc, x, y, z, 0, RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X); + + const Element *e = alloc->mHal.state.type->getElement()->getField(cIdx); + ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx); + + if (alloc->mHal.state.hasReferences) { + e->incRefs(data); + e->decRefs(ptr); + } + + memcpy(ptr, data, sizeBytes); +} + +void rsovAllocationElementRead(const Context *rsc, const Allocation *alloc, + uint32_t x, uint32_t y, uint32_t z, void *data, + uint32_t cIdx, size_t sizeBytes) { + uint8_t *ptr = + GetOffsetPtr(alloc, x, y, z, 0, RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X); + + const Element *e = alloc->mHal.state.type->getElement()->getField(cIdx); + ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx); + + memcpy(data, ptr, sizeBytes); +} diff --git a/rsov/driver/rsovAllocation.h b/rsov/driver/rsovAllocation.h new file mode 100644 index 00000000..24f4cf0a --- /dev/null +++ b/rsov/driver/rsovAllocation.h @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RSOV_ALLOCATION_H +#define RSOV_ALLOCATION_H + +#include <vulkan/vulkan.h> + +#include "rsDefines.h" +#include "rs_hal.h" +#include "system/window.h" + +namespace android { +namespace renderscript { + +class Allocation; +class Context; +class Type; + +namespace rsov { + +class RSoVContext; + +class RSoVAllocation { + public: + RSoVAllocation(RSoVContext *context, const Type *type); + ~RSoVAllocation(); + + uint32_t getWidth() const { return mWidth; } + uint32_t getHeight() const { return mHeight; } + uint32_t getDepth() const { return mDepth; } + const VkDescriptorImageInfo *getImageInfo() const { return &mImageInfo; } + char *getHostPtr() const { return mPtr; } + + private: + void InitImage(); + + char *mPtr; // Host pointer to mmapped device memory for the Allocation + RSoVContext *mRSoV; + VkDevice mDevice; + const Type *mType; + const uint32_t mWidth; + const uint32_t mHeight; + const uint32_t mDepth; + + VkFormat mFormat; + VkDescriptorImageInfo mImageInfo; + VkDeviceMemory mMem; + VkImage mImage; + VkImageView mImageView; + VkImageLayout mImageLayout; + + // TODO: add an underneath buffer too +}; + +} // namespace rsov +} // namespace renderscript +} // namespace android + +extern bool rsovAllocationInit(const android::renderscript::Context *rsc, + android::renderscript::Allocation *alloc, + bool forceZero); + +extern void rsovAllocationDestroy(const android::renderscript::Context *rsc, + android::renderscript::Allocation *alloc); + +extern void rsovAllocationData1D(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + uint32_t xoff, uint32_t lod, size_t count, + const void *data, size_t sizeBytes); + +extern void rsovAllocationData2D(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t lod, + RsAllocationCubemapFace face, uint32_t w, + uint32_t h, const void *data, size_t sizeBytes, + size_t stride); + +extern void rsovAllocationData3D(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t zoff, + uint32_t lod, uint32_t w, uint32_t h, + uint32_t d, const void *data, size_t sizeBytes, + size_t stride); + +extern void rsovAllocationRead1D(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + uint32_t xoff, uint32_t lod, size_t count, + void *data, size_t sizeBytes); + +extern void rsovAllocationRead2D(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t lod, + RsAllocationCubemapFace face, uint32_t w, + uint32_t h, void *data, size_t sizeBytes, + size_t stride); + +extern void rsovAllocationRead3D(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + uint32_t xoff, uint32_t yoff, uint32_t zoff, + uint32_t lod, uint32_t w, uint32_t h, + uint32_t d, void *data, size_t sizeBytes, + size_t stride); + +extern void *rsovAllocationLock1D( + const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc); + +extern void rsovAllocationUnlock1D( + const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc); + +extern void rsovAllocationData1D_alloc( + const android::renderscript::Context *rsc, + const android::renderscript::Allocation *dstAlloc, uint32_t dstXoff, + uint32_t dstLod, size_t count, + const android::renderscript::Allocation *srcAlloc, uint32_t srcXoff, + uint32_t srcLod); + +extern void rsovAllocationData2D_alloc_script( + const android::renderscript::Context *rsc, + const android::renderscript::Allocation *dstAlloc, uint32_t dstXoff, + uint32_t dstYoff, uint32_t dstLod, RsAllocationCubemapFace dstFace, + uint32_t w, uint32_t h, const android::renderscript::Allocation *srcAlloc, + uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod, + RsAllocationCubemapFace srcFace); + +extern void rsovAllocationData2D_alloc( + const android::renderscript::Context *rsc, + const android::renderscript::Allocation *dstAlloc, uint32_t dstXoff, + uint32_t dstYoff, uint32_t dstLod, RsAllocationCubemapFace dstFace, + uint32_t w, uint32_t h, const android::renderscript::Allocation *srcAlloc, + uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod, + RsAllocationCubemapFace srcFace); + +extern void rsovAllocationData3D_alloc_script( + const android::renderscript::Context *rsc, + const android::renderscript::Allocation *dstAlloc, uint32_t dstXoff, + uint32_t dstYoff, uint32_t dstZoff, uint32_t dstLod, uint32_t w, uint32_t h, + uint32_t d, const android::renderscript::Allocation *srcAlloc, + uint32_t srcXoff, uint32_t srcYoff, uint32_t srcZoff, uint32_t srcLod); + +extern void rsovAllocationData3D_alloc( + const android::renderscript::Context *rsc, + const android::renderscript::Allocation *dstAlloc, uint32_t dstXoff, + uint32_t dstYoff, uint32_t dstZoff, uint32_t dstLod, uint32_t w, uint32_t h, + uint32_t d, const android::renderscript::Allocation *srcAlloc, + uint32_t srcXoff, uint32_t srcYoff, uint32_t srcZoff, uint32_t srcLod); + +extern void rsovAllocationAdapterOffset( + const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc); + +extern bool rsovAllocationAdapterInit(const android::renderscript::Context *rsc, + android::renderscript::Allocation *alloc); + +extern void rsovAllocationSyncAll( + const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, RsAllocationUsageType src); + +extern void rsovAllocationMarkDirty( + const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc); + +extern void rsovAllocationResize(const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + const android::renderscript::Type *newType, + bool zeroNew); + +extern void rsovAllocationGenerateMipmaps( + const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc); + +extern uint32_t rsovAllocationGrallocBits( + const android::renderscript::Context *rsc, + android::renderscript::Allocation *alloc); + +extern void rsovAllocationUpdateCachedObject( + const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, + android::renderscript::rs_allocation *obj); + +extern void rsovAllocationSetSurface(const android::renderscript::Context *rsc, + android::renderscript::Allocation *alloc, + ANativeWindow *nw); + +extern void rsovAllocationIoSend(const android::renderscript::Context *rsc, + android::renderscript::Allocation *alloc); + +extern void rsovAllocationIoReceive(const android::renderscript::Context *rsc, + android::renderscript::Allocation *alloc); + +extern void rsovAllocationElementData( + const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, uint32_t x, uint32_t y, + uint32_t z, const void *data, uint32_t cIdx, size_t sizeBytes); + +extern void rsovAllocationElementRead( + const android::renderscript::Context *rsc, + const android::renderscript::Allocation *alloc, uint32_t x, uint32_t y, + uint32_t z, void *data, uint32_t cIdx, size_t sizeBytes); + +#endif // RSOV_ALLOCATION_H diff --git a/rsov/driver/rsovContext.cpp b/rsov/driver/rsovContext.cpp new file mode 100644 index 00000000..f1bfc66e --- /dev/null +++ b/rsov/driver/rsovContext.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rsovContext.h" + +#include <vector> + +#include "rsUtils.h" + +namespace android { +namespace renderscript { +namespace rsov { + +RSoVContext* RSoVContext::mContext = nullptr; +std::once_flag RSoVContext::mInitFlag; + +void RSoVContext::Initialize(char const* const name) { + // Initialize instance + VkApplicationInfo appInfo = { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pNext = nullptr, + .pApplicationName = name, // TODO: set to app name + .applicationVersion = 1, + .pEngineName = name, + .engineVersion = 1, + .apiVersion = VK_API_VERSION_1_0}; + + VkInstanceCreateInfo instInfo = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .pApplicationInfo = &appInfo, + }; + + VkResult res; + res = vkCreateInstance(&instInfo, nullptr, &mInstance); + rsAssert(res == VK_SUCCESS); + + // Enumerate devices + uint32_t gpu_count; + + res = vkEnumeratePhysicalDevices(mInstance, &gpu_count, nullptr); + rsAssert(gpu_count > 0); + + std::vector<VkPhysicalDevice> GPUs(gpu_count); + + res = vkEnumeratePhysicalDevices(mInstance, &gpu_count, GPUs.data()); + rsAssert(res == VK_SUCCESS && gpu_count > 0); + + mGPU = GPUs[0]; + + // Get device memory properties + vkGetPhysicalDeviceMemoryProperties(mGPU, &mMemoryProperties); + + // Initialize device + + float queuePriorities[] = {0.0}; + + VkDeviceQueueCreateInfo queueInfo = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .pNext = nullptr, + .queueCount = 1, + .pQueuePriorities = queuePriorities, + }; + + VkDeviceCreateInfo deviceInfo = { + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pNext = nullptr, + .queueCreateInfoCount = 1, + .pQueueCreateInfos = &queueInfo, + .pEnabledFeatures = nullptr, + }; + + res = vkCreateDevice(mGPU, &deviceInfo, nullptr, &mDevice); + rsAssert(res == VK_SUCCESS); + + // Initialize queue family index + uint32_t queueCount; + + vkGetPhysicalDeviceQueueFamilyProperties(mGPU, &queueCount, nullptr); + rsAssert(queueCount > 0); + + std::vector<VkQueueFamilyProperties> queueProps(queueCount); + + vkGetPhysicalDeviceQueueFamilyProperties(mGPU, &queueCount, + queueProps.data()); + rsAssert(queueCount > 0); + + uint32_t queueFamilyIndex = UINT_MAX; + bool found = false; + for (unsigned int i = 0; i < queueCount; i++) { + if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { + queueFamilyIndex = i; + found = true; + break; + } + } + + rsAssert(found); + + // Create a device queue + + vkGetDeviceQueue(mDevice, queueFamilyIndex, 0, &mQueue); + + // Create command pool + + VkCommandPoolCreateInfo cmd_pool_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .pNext = nullptr, + .queueFamilyIndex = queueFamilyIndex, + .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + }; + + res = vkCreateCommandPool(mDevice, &cmd_pool_info, nullptr, &mCmdPool); + rsAssert(res == VK_SUCCESS); +} + +bool RSoVContext::MemoryTypeFromProperties(uint32_t typeBits, + VkFlags requirements_mask, + uint32_t* typeIndex) { + for (uint32_t i = 0; i < 32; i++) { + if ((typeBits & 1) == 1) { + const uint32_t prop = mMemoryProperties.memoryTypes[i].propertyFlags; + if ((prop & requirements_mask) == requirements_mask) { + *typeIndex = i; + return true; + } + } + typeBits >>= 1; + } + + return false; +} + +RSoVContext::RSoVContext() { + char engineName[] = "RSoV"; + + Initialize(engineName); +} + +RSoVContext::~RSoVContext() { + vkDestroyCommandPool(mDevice, mCmdPool, nullptr); + vkDestroyDevice(mDevice, nullptr); + vkDestroyInstance(mInstance, nullptr); +} + +RSoVContext* RSoVContext::create() { + std::call_once(mInitFlag, []() { mContext = new RSoVContext(); }); + return mContext; +} + +} // namespace rsov +} // namespace renderscript +} // namespace android diff --git a/rsov/driver/rsovContext.h b/rsov/driver/rsovContext.h new file mode 100644 index 00000000..cf8e30bd --- /dev/null +++ b/rsov/driver/rsovContext.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RSOV_CONTEXT_H +#define RSOV_CONTEXT_H + +#include <vulkan/vulkan.h> +#include <mutex> + +namespace android { +namespace renderscript { + +class RsdCpuReference; + +namespace rsov { + +class RSoVContext { + public: + static RSoVContext* create(); + ~RSoVContext(); + + VkDevice getDevice() const { return mDevice; } + VkQueue getQueue() const { return mQueue; } + VkCommandPool getCmdPool() const { return mCmdPool; } + + bool MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, + uint32_t* typeIndex); + + private: + RSoVContext(); + + void Initialize(char const* const name); + + static RSoVContext* mContext; + static std::once_flag mInitFlag; + + VkInstance mInstance; + VkPhysicalDevice mGPU; + VkDevice mDevice; + VkPhysicalDeviceMemoryProperties mMemoryProperties; + VkQueue mQueue; + VkCommandPool mCmdPool; +}; + +} // namespace rsov +} // namespace renderscript +} // namespace android + +#endif // RSOV_CONTEXT_H diff --git a/rsov/driver/rsovCore.cpp b/rsov/driver/rsovCore.cpp new file mode 100644 index 00000000..b51fa391 --- /dev/null +++ b/rsov/driver/rsovCore.cpp @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rsovCore.h" + +#include <malloc.h> +#include <sched.h> +#include <string.h> +#include <sys/resource.h> +#include <sys/syscall.h> +#include <sys/types.h> + +#include "cpu_ref/rsd_cpu.h" +#include "rsContext.h" +#include "rsovAllocation.h" +#include "rsovContext.h" +#include "rsovElement.h" +#include "rsovSampler.h" +#include "rsovScript.h" +#include "rsovScriptGroup.h" +#include "rsovType.h" + +namespace android { +namespace renderscript { + +namespace { +void SetPriority(const Context *rsc, int32_t priority) { + RSoVHal *dc = (RSoVHal *)rsc->mHal.drv; + + dc->mCpuRef->setPriority(priority); +} + +void Shutdown(Context *rsc) { + RSoVHal *dc = (RSoVHal *)rsc->mHal.drv; + delete dc->mCpuRef; + free(dc); + rsc->mHal.drv = nullptr; +} + +void *AllocRuntimeMem(size_t size, uint32_t flags) { + void* buffer = calloc(size, sizeof(char)); + return buffer; +} + +void FreeRuntimeMem(void* ptr) { + free(ptr); +} + +const RsdCpuReference::CpuSymbol *rsdLookupRuntimeStub( + Context *pContext, char const *name) { + return nullptr; +} + +RsdCpuReference::CpuScript *LookupScript(Context *, const Script *s) { + return (RsdCpuReference::CpuScript *)s->mHal.drv; +} + +} // anonymous namespace + +extern "C" bool rsdHalQueryHal(RsHalInitEnums entry, void **fnPtr) { + switch (entry) { + case RS_HAL_ALLOCATION_INIT: + fnPtr[0] = (void *)rsovAllocationInit; + break; + case RS_HAL_ALLOCATION_INIT_OEM: + fnPtr[0] = (void *)nullptr; + break; + case RS_HAL_ALLOCATION_INIT_ADAPTER: + fnPtr[0] = (void *)rsovAllocationAdapterInit; + break; + case RS_HAL_ALLOCATION_DESTROY: + fnPtr[0] = (void *)rsovAllocationDestroy; + break; + case RS_HAL_ALLOCATION_GET_GRALLOC_BITS: + fnPtr[0] = (void *)rsovAllocationGrallocBits; + break; + case RS_HAL_ALLOCATION_DATA_1D: + fnPtr[0] = (void *)rsovAllocationData1D; + break; + case RS_HAL_ALLOCATION_DATA_2D: + fnPtr[0] = (void *)rsovAllocationData2D; + break; + case RS_HAL_ALLOCATION_DATA_3D: + fnPtr[0] = (void *)rsovAllocationData3D; + break; + case RS_HAL_ALLOCATION_READ_1D: + fnPtr[0] = (void *)rsovAllocationRead1D; + break; + case RS_HAL_ALLOCATION_READ_2D: + fnPtr[0] = (void *)rsovAllocationRead2D; + break; + case RS_HAL_ALLOCATION_READ_3D: + fnPtr[0] = (void *)rsovAllocationRead3D; + break; + case RS_HAL_ALLOCATION_LOCK_1D: + fnPtr[0] = (void *)rsovAllocationLock1D; + break; + case RS_HAL_ALLOCATION_UNLOCK_1D: + fnPtr[0] = (void *)rsovAllocationUnlock1D; + break; + case RS_HAL_ALLOCATION_COPY_1D: + fnPtr[0] = (void *)rsovAllocationData1D_alloc; + break; + case RS_HAL_ALLOCATION_COPY_2D: + fnPtr[0] = (void *)rsovAllocationData2D_alloc; + break; + case RS_HAL_ALLOCATION_COPY_3D: + fnPtr[0] = (void *)rsovAllocationData3D_alloc; + break; + case RS_HAL_ALLOCATION_ADAPTER_OFFSET: + fnPtr[0] = (void *)rsovAllocationAdapterOffset; + break; + case RS_HAL_ALLOCATION_RESIZE: + fnPtr[0] = (void *)rsovAllocationResize; + break; + case RS_HAL_ALLOCATION_SYNC_ALL: + fnPtr[0] = (void *)rsovAllocationSyncAll; + break; + case RS_HAL_ALLOCATION_MARK_DIRTY: + fnPtr[0] = (void *)rsovAllocationMarkDirty; + break; + case RS_HAL_ALLOCATION_GENERATE_MIPMAPS: + fnPtr[0] = (void *)rsovAllocationGenerateMipmaps; + break; + case RS_HAL_ALLOCATION_UPDATE_CACHED_OBJECT: + fnPtr[0] = (void *)rsovAllocationUpdateCachedObject; + break; + case RS_HAL_ALLOCATION_GET_POINTER: + fnPtr[0] = (void *)nullptr; + break; + case RS_HAL_ALLOCATION_SET_SURFACE: + fnPtr[0] = (void *)rsovAllocationSetSurface; + break; + case RS_HAL_ALLOCATION_IO_SEND: + fnPtr[0] = (void *)rsovAllocationIoSend; + break; + case RS_HAL_ALLOCATION_IO_RECEIVE: + fnPtr[0] = (void *)rsovAllocationIoReceive; + break; + case RS_HAL_ALLOCATION_ELEMENT_DATA: + fnPtr[0] = (void *)rsovAllocationElementData; + break; + case RS_HAL_ALLOCATION_ELEMENT_READ: + fnPtr[0] = (void *)rsovAllocationElementRead; + break; + + case RS_HAL_CORE_SHUTDOWN: + fnPtr[0] = (void *)Shutdown; + break; + case RS_HAL_CORE_SET_PRIORITY: + fnPtr[0] = (void *)SetPriority; + break; + case RS_HAL_CORE_ALLOC_RUNTIME_MEM: + fnPtr[0] = (void *)AllocRuntimeMem; + break; + case RS_HAL_CORE_FREE_RUNTIME_MEM: + fnPtr[0] = (void *)FreeRuntimeMem; + break; + case RS_HAL_CORE_FINISH: + fnPtr[0] = (void *)nullptr; + break; + + case RS_HAL_SCRIPT_INIT: + fnPtr[0] = (void *)rsovScriptInit; + break; + case RS_HAL_SCRIPT_INIT_INTRINSIC: + fnPtr[0] = (void *)rsovInitIntrinsic; + break; + case RS_HAL_SCRIPT_INVOKE_FUNCTION: + fnPtr[0] = (void *)rsovScriptInvokeFunction; + break; + case RS_HAL_SCRIPT_INVOKE_ROOT: + fnPtr[0] = (void *)rsovScriptInvokeRoot; + break; + case RS_HAL_SCRIPT_INVOKE_FOR_EACH: + fnPtr[0] = (void *)rsovScriptInvokeForEach; + break; + case RS_HAL_SCRIPT_INVOKE_INIT: + fnPtr[0] = (void *)rsovScriptInvokeInit; + break; + case RS_HAL_SCRIPT_INVOKE_FREE_CHILDREN: + fnPtr[0] = (void *)rsovScriptInvokeFreeChildren; + break; + case RS_HAL_SCRIPT_DESTROY: + fnPtr[0] = (void *)rsovScriptDestroy; + break; + case RS_HAL_SCRIPT_SET_GLOBAL_VAR: + fnPtr[0] = (void *)rsovScriptSetGlobalVar; + break; + case RS_HAL_SCRIPT_GET_GLOBAL_VAR: + fnPtr[0] = (void *)rsovScriptGetGlobalVar; + break; + case RS_HAL_SCRIPT_SET_GLOBAL_VAR_WITH_ELEMENT_DIM: + fnPtr[0] = (void *)rsovScriptSetGlobalVarWithElemDims; + break; + case RS_HAL_SCRIPT_SET_GLOBAL_BIND: + fnPtr[0] = (void *)rsovScriptSetGlobalBind; + break; + case RS_HAL_SCRIPT_SET_GLOBAL_OBJECT: + fnPtr[0] = (void *)rsovScriptSetGlobalObj; + break; + case RS_HAL_SCRIPT_INVOKE_FOR_EACH_MULTI: + fnPtr[0] = (void *)rsovScriptInvokeForEachMulti; + break; + case RS_HAL_SCRIPT_UPDATE_CACHED_OBJECT: + fnPtr[0] = (void *)rsovScriptUpdateCachedObject; + break; + case RS_HAL_SCRIPT_INVOKE_REDUCE: + fnPtr[0] = (void *)rsovScriptInvokeReduce; + break; + + case RS_HAL_SAMPLER_INIT: + fnPtr[0] = (void *)rsovSamplerInit; + break; + case RS_HAL_SAMPLER_DESTROY: + fnPtr[0] = (void *)rsovSamplerDestroy; + break; + case RS_HAL_SAMPLER_UPDATE_CACHED_OBJECT: + fnPtr[0] = (void *)rsovSamplerUpdateCachedObject; + break; + + case RS_HAL_TYPE_INIT: + fnPtr[0] = (void *)rsovTypeInit; + break; + case RS_HAL_TYPE_DESTROY: + fnPtr[0] = (void *)rsovTypeDestroy; + break; + case RS_HAL_TYPE_UPDATE_CACHED_OBJECT: + fnPtr[0] = (void *)rsovTypeUpdateCachedObject; + break; + + case RS_HAL_ELEMENT_INIT: + fnPtr[0] = (void *)rsovElementInit; + break; + case RS_HAL_ELEMENT_DESTROY: + fnPtr[0] = (void *)rsovElementDestroy; + break; + case RS_HAL_ELEMENT_UPDATE_CACHED_OBJECT: + fnPtr[0] = (void *)rsovElementUpdateCachedObject; + break; + + case RS_HAL_SCRIPT_GROUP_INIT: + fnPtr[0] = (void *)rsovScriptGroupInit; + break; + case RS_HAL_SCRIPT_GROUP_DESTROY: + fnPtr[0] = (void *)rsovScriptGroupDestroy; + break; + case RS_HAL_SCRIPT_GROUP_UPDATE_CACHED_OBJECT: + fnPtr[0] = (void *)nullptr; + break; + case RS_HAL_SCRIPT_GROUP_SET_INPUT: + fnPtr[0] = (void *)rsovScriptGroupSetInput; + break; + case RS_HAL_SCRIPT_GROUP_SET_OUTPUT: + fnPtr[0] = (void *)rsovScriptGroupSetOutput; + break; + case RS_HAL_SCRIPT_GROUP_EXECUTE: + fnPtr[0] = (void *)rsovScriptGroupExecute; + break; + + // Ignore entries for the legacy graphics api, + + default: + ALOGE("ERROR: unknown RenderScript HAL API query, %i", entry); + return false; + } + + return true; +} + +extern "C" void rsdHalAbort(RsContext) {} + +extern "C" bool rsdHalQueryVersion(uint32_t *major, uint32_t *minor) { + *major = RS_HAL_VERSION; + *minor = 0; + return true; +} + +extern "C" bool rsdHalInit(RsContext c, uint32_t version_major, + uint32_t version_minor) { + Context *rsc = (Context *)c; + + RSoVHal *hal = new RSoVHal(); + if (!hal) { + ALOGE("Failed creating RSoV driver hal."); + return false; + } + rsc->mHal.drv = hal; + + hal->mCpuRef = RsdCpuReference::create(rsc, version_major, version_minor, + &rsdLookupRuntimeStub, &LookupScript); + if (!hal->mCpuRef) { + ALOGE("RsdCpuReference::create for driver hal failed."); + rsc->mHal.drv = nullptr; + return false; + } + + hal->mRSoV = android::renderscript::rsov::RSoVContext::create(); + if (!hal->mRSoV) { + ALOGE("RsdCpuReference::create for driver hal failed."); + rsc->mHal.drv = nullptr; + return false; + } + + return true; +} + +} // namespace renderscript +} // namespace android diff --git a/rsov/driver/rsovCore.h b/rsov/driver/rsovCore.h new file mode 100644 index 00000000..d0c160d5 --- /dev/null +++ b/rsov/driver/rsovCore.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RSOV_CORE_H +#define RSOV_CORE_H + +namespace android { +namespace renderscript { + +class RsdCpuReference; + +namespace rsov { + +class RSoVContext; + +} // namespace rsov +} // namespace renderscript +} // namespace android + +struct RSoVHal { + android::renderscript::rsov::RSoVContext* mRSoV; + android::renderscript::RsdCpuReference *mCpuRef; +}; + +#define NELEM(x) (sizeof(x) / sizeof((x)[0])) + +#endif diff --git a/rsov/driver/rsovElement.cpp b/rsov/driver/rsovElement.cpp new file mode 100644 index 00000000..d6321b34 --- /dev/null +++ b/rsov/driver/rsovElement.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rsContext.h" +#include "rsElement.h" + +using android::renderscript::Context; +using android::renderscript::Element; +using android::renderscript::rs_element; + +bool rsovElementInit(const Context *rsc, const Element *e) { return true; } + +void rsovElementDestroy(const Context *rsc, const Element *e) {} + +void rsovElementUpdateCachedObject(const Context *rsc, const Element *element, + rs_element *obj) { + obj->p = element; +#ifdef __LP64__ + obj->r = nullptr; + obj->v1 = nullptr; + obj->v2 = nullptr; +#endif +} diff --git a/rsov/driver/rsovElement.h b/rsov/driver/rsovElement.h new file mode 100644 index 00000000..e3d46bcd --- /dev/null +++ b/rsov/driver/rsovElement.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RSOV_ELEMENT_H +#define RSOV_ELEMENT_H + +#include "rs_hal.h" + +extern bool rsovElementInit(const android::renderscript::Context *rsc, + const android::renderscript::Element *); + +extern void rsovElementDestroy(const android::renderscript::Context *rsc, + const android::renderscript::Element *); + +extern void rsovElementUpdateCachedObject( + const android::renderscript::Context *rsc, + const android::renderscript::Element *, + android::renderscript::rs_element *obj); + +#endif // RSOV_ELEMENT_H diff --git a/rsov/driver/rsovRuntimeStubs.cpp b/rsov/driver/rsovRuntimeStubs.cpp new file mode 100644 index 00000000..308c0a53 --- /dev/null +++ b/rsov/driver/rsovRuntimeStubs.cpp @@ -0,0 +1,1150 @@ +/* + * Copyright (C) 2011-2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <time.h> + +#include "rsContext.h" +#include "rsElement.h" +#include "rsMatrix2x2.h" +#include "rsMatrix3x3.h" +#include "rsMatrix4x4.h" +#include "rsRuntime.h" +#include "rsScriptC.h" +#include "rsType.h" +#include "rsovAllocation.h" +#include "rsovCore.h" +#include "rsovScript.h" + +using namespace android; +using namespace android::renderscript; + +typedef __fp16 half; +typedef half half2 __attribute__((ext_vector_type(2))); +typedef half half3 __attribute__((ext_vector_type(3))); +typedef half half4 __attribute__((ext_vector_type(4))); + +typedef float float2 __attribute__((ext_vector_type(2))); +typedef float float3 __attribute__((ext_vector_type(3))); +typedef float float4 __attribute__((ext_vector_type(4))); +typedef double double2 __attribute__((ext_vector_type(2))); +typedef double double3 __attribute__((ext_vector_type(3))); +typedef double double4 __attribute__((ext_vector_type(4))); +typedef char char2 __attribute__((ext_vector_type(2))); +typedef char char3 __attribute__((ext_vector_type(3))); +typedef char char4 __attribute__((ext_vector_type(4))); +typedef unsigned char uchar2 __attribute__((ext_vector_type(2))); +typedef unsigned char uchar3 __attribute__((ext_vector_type(3))); +typedef unsigned char uchar4 __attribute__((ext_vector_type(4))); +typedef int16_t short2 __attribute__((ext_vector_type(2))); +typedef int16_t short3 __attribute__((ext_vector_type(3))); +typedef int16_t short4 __attribute__((ext_vector_type(4))); +typedef uint16_t ushort2 __attribute__((ext_vector_type(2))); +typedef uint16_t ushort3 __attribute__((ext_vector_type(3))); +typedef uint16_t ushort4 __attribute__((ext_vector_type(4))); +typedef int32_t int2 __attribute__((ext_vector_type(2))); +typedef int32_t int3 __attribute__((ext_vector_type(3))); +typedef int32_t int4 __attribute__((ext_vector_type(4))); +typedef uint32_t uint2 __attribute__((ext_vector_type(2))); +typedef uint32_t uint3 __attribute__((ext_vector_type(3))); +typedef uint32_t uint4 __attribute__((ext_vector_type(4))); +typedef int64_t long2 __attribute__((ext_vector_type(2))); +typedef int64_t long3 __attribute__((ext_vector_type(3))); +typedef int64_t long4 __attribute__((ext_vector_type(4))); +typedef uint64_t ulong2 __attribute__((ext_vector_type(2))); +typedef uint64_t ulong3 __attribute__((ext_vector_type(3))); +typedef uint64_t ulong4 __attribute__((ext_vector_type(4))); + +typedef uint8_t uchar; +typedef uint16_t ushort; +typedef uint32_t uint; +#ifndef RS_SERVER +typedef uint64_t ulong; +#endif + +// Add NOLINT to suppress wrong warnings from clang-tidy. +#ifndef __LP64__ +#define OPAQUETYPE(t) \ + typedef struct { \ + const int *const p; \ + } __attribute__((packed, aligned(4))) t; /*NOLINT*/ +#else +#define OPAQUETYPE(t) \ + typedef struct { \ + const void *p; \ + const void *r; \ + const void *v1; \ + const void *v2; \ + } t; /*NOLINT*/ +#endif + +OPAQUETYPE(rs_element) +OPAQUETYPE(rs_type) +OPAQUETYPE(rs_allocation) +OPAQUETYPE(rs_sampler) +OPAQUETYPE(rs_script) +OPAQUETYPE(rs_script_call) + +OPAQUETYPE(rs_program_fragment); +OPAQUETYPE(rs_program_store); +OPAQUETYPE(rs_program_vertex); +OPAQUETYPE(rs_program_raster); +OPAQUETYPE(rs_mesh); +OPAQUETYPE(rs_font); + +#undef OPAQUETYPE + +typedef enum { + // 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 { + int tm_sec; ///< seconds + int tm_min; ///< minutes + int tm_hour; ///< hours + int tm_mday; ///< day of the month + int tm_mon; ///< month + int tm_year; ///< year + int tm_wday; ///< day of the week + int tm_yday; ///< day of the year + int tm_isdst; ///< daylight savings time +} rs_tm; + +// Some RS functions are not threadsafe but can be called from an invoke +// function. Instead of summarily marking scripts that call these functions as +// not-threadable we detect calls to them in the driver and sends a fatal error +// message. +static bool failIfInKernel(Context *rsc, const char *funcName) { + RSoVHal *dc = (RSoVHal *)rsc->mHal.drv; + RsdCpuReference *impl = (RsdCpuReference *)dc->mCpuRef; + + if (impl->getInKernel()) { + char buf[256]; + snprintf(buf, sizeof(buf), + "Error: Call to unsupported function %s " + "in kernel", + funcName); + rsc->setError(RS_ERROR_FATAL_DRIVER, buf); + return true; + } + return false; +} + +////////////////////////////////////////////////////////////////////////////// +// Allocation routines +////////////////////////////////////////////////////////////////////////////// +#if defined(__i386__) || (defined(__mips__) && __mips == 32) +// i386 and MIPS32 have different struct return passing to ARM; emulate with a +// pointer +const Allocation *rsGetAllocation(const void *ptr) { + Context *rsc = RsdCpuReference::getTlsContext(); + const Script *sc = RsdCpuReference::getTlsScript(); + Allocation *alloc = rsovScriptGetAllocationForPointer(rsc, sc, ptr); + android::renderscript::rs_allocation obj = {0}; + alloc->callUpdateCacheObject(rsc, &obj); + return (Allocation *)obj.p; +} +#else +const android::renderscript::rs_allocation rsGetAllocation(const void *ptr) { + Context *rsc = RsdCpuReference::getTlsContext(); + const Script *sc = RsdCpuReference::getTlsScript(); + Allocation *alloc = rsovScriptGetAllocationForPointer(rsc, sc, ptr); + +#ifndef __LP64__ // ARMv7 + android::renderscript::rs_allocation obj = {0}; +#else // AArch64/x86_64/MIPS64 + android::renderscript::rs_allocation obj = {0, 0, 0, 0}; +#endif + alloc->callUpdateCacheObject(rsc, &obj); + return obj; +} +#endif + +void __attribute__((overloadable)) rsAllocationIoSend(::rs_allocation a) { + Context *rsc = RsdCpuReference::getTlsContext(); + if (failIfInKernel(rsc, "rsAllocationIoSend")) return; + rsrAllocationIoSend(rsc, (Allocation *)a.p); +} + +void __attribute__((overloadable)) rsAllocationIoReceive(::rs_allocation a) { + Context *rsc = RsdCpuReference::getTlsContext(); + if (failIfInKernel(rsc, "rsAllocationIoReceive")) return; + rsrAllocationIoReceive(rsc, (Allocation *)a.p); +} + +void __attribute__((overloadable)) +rsAllocationCopy1DRange(::rs_allocation dstAlloc, uint32_t dstOff, + uint32_t dstMip, uint32_t count, + ::rs_allocation srcAlloc, uint32_t srcOff, + uint32_t srcMip) { + Context *rsc = RsdCpuReference::getTlsContext(); + if (failIfInKernel(rsc, "rsAllocationCopy1DRange")) return; + rsrAllocationCopy1DRange(rsc, (Allocation *)dstAlloc.p, dstOff, dstMip, count, + (Allocation *)srcAlloc.p, srcOff, srcMip); +} + +void __attribute__((overloadable)) +rsAllocationCopy2DRange(::rs_allocation dstAlloc, uint32_t dstXoff, + uint32_t dstYoff, uint32_t dstMip, + rs_allocation_cubemap_face dstFace, uint32_t width, + uint32_t height, ::rs_allocation srcAlloc, + uint32_t srcXoff, uint32_t srcYoff, uint32_t srcMip, + rs_allocation_cubemap_face srcFace) { + Context *rsc = RsdCpuReference::getTlsContext(); + if (failIfInKernel(rsc, "rsAllocationCopy2DRange")) return; + rsrAllocationCopy2DRange( + rsc, (Allocation *)dstAlloc.p, dstXoff, dstYoff, dstMip, dstFace, width, + height, (Allocation *)srcAlloc.p, 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); + + // Any new rsObject created from inside a script should have the usrRefCount + // initialized to 0 and the sysRefCount initialized to 1. + element->incSysRef(); + element->decUserRef(); + + 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); + + // Any new rsObject created from inside a script should have the usrRefCount + // initialized to 0 and the sysRefCount initialized to 1. + type->incSysRef(); + type->decUserRef(); + + 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); + + // Any new rsObject created from inside a script should have the usrRefCount + // initialized to 0 and the sysRefCount initialized to 1. + alloc->incSysRef(); + alloc->decUserRef(); + + 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 +////////////////////////////////////////////////////////////////////////////// +// Add NOLINT to suppress wrong warnings from clang-tidy. +#define IS_CLEAR_SET_OBJ(t) \ + bool rsIsObject(t src) { return src.p != nullptr; } \ + void __attribute__((overloadable)) rsClearObject(t *dst) { /*NOLINT*/ \ + rsrClearObject(reinterpret_cast<rs_object_base *>(dst)); \ + } \ + void __attribute__((overloadable)) rsSetObject(t *dst, t src) { /*NOLINT*/ \ + Context *rsc = RsdCpuReference::getTlsContext(); \ + rsrSetObject(rsc, reinterpret_cast<rs_object_base *>(dst), \ + (ObjectBase *)src.p); \ + } + +IS_CLEAR_SET_OBJ(::rs_element) +IS_CLEAR_SET_OBJ(::rs_type) +IS_CLEAR_SET_OBJ(::rs_allocation) +IS_CLEAR_SET_OBJ(::rs_sampler) +IS_CLEAR_SET_OBJ(::rs_script) + +IS_CLEAR_SET_OBJ(::rs_mesh) +IS_CLEAR_SET_OBJ(::rs_program_fragment) +IS_CLEAR_SET_OBJ(::rs_program_vertex) +IS_CLEAR_SET_OBJ(::rs_program_raster) +IS_CLEAR_SET_OBJ(::rs_program_store) +IS_CLEAR_SET_OBJ(::rs_font) + +#undef IS_CLEAR_SET_OBJ + +////////////////////////////////////////////////////////////////////////////// +// Element routines +////////////////////////////////////////////////////////////////////////////// +static void *ElementAt(Allocation *a, RsDataType dt, uint32_t vecSize, + uint32_t x, uint32_t y, uint32_t z) { + Context *rsc = RsdCpuReference::getTlsContext(); + const Type *t = a->getType(); + const Element *e = t->getElement(); + + char buf[256]; + if (x && (x >= t->getLODDimX(0))) { + snprintf(buf, sizeof(buf), "Out range ElementAt X %i of %i", x, + t->getLODDimX(0)); + rsc->setError(RS_ERROR_FATAL_DEBUG, buf); + return nullptr; + } + + if (y && (y >= t->getLODDimY(0))) { + snprintf(buf, sizeof(buf), "Out range ElementAt Y %i of %i", y, + t->getLODDimY(0)); + rsc->setError(RS_ERROR_FATAL_DEBUG, buf); + return nullptr; + } + + if (z && (z >= t->getLODDimZ(0))) { + snprintf(buf, sizeof(buf), "Out range ElementAt Z %i of %i", z, + t->getLODDimZ(0)); + rsc->setError(RS_ERROR_FATAL_DEBUG, buf); + return nullptr; + } + + if (vecSize > 0) { + if (vecSize != e->getVectorSize()) { + snprintf(buf, sizeof(buf), "Vector size mismatch for ElementAt %i of %i", + vecSize, e->getVectorSize()); + rsc->setError(RS_ERROR_FATAL_DEBUG, buf); + return nullptr; + } + + if (dt != e->getType()) { + snprintf(buf, sizeof(buf), "Data type mismatch for ElementAt %i of %i", + dt, e->getType()); + rsc->setError(RS_ERROR_FATAL_DEBUG, buf); + return nullptr; + } + } + + uint8_t *p = (uint8_t *)a->mHal.drvState.lod[0].mallocPtr; + const uint32_t eSize = e->getSizeBytes(); + const uint32_t stride = a->mHal.drvState.lod[0].stride; + const uint32_t dimY = a->mHal.drvState.lod[0].dimY; + return &p[(x * eSize) + (y * stride) + (z * stride * dimY)]; +} + +void rsSetElementAt(::rs_allocation a, const void *ptr, uint32_t x, uint32_t y, + uint32_t z) { + const Type *t = const_cast<Allocation *>((Allocation *)a.p)->getType(); + const Element *e = t->getElement(); + void *tmp = ElementAt((Allocation *)a.p, RS_TYPE_UNSIGNED_8, 0, x, y, z); + if (tmp != nullptr) memcpy(tmp, ptr, e->getSizeBytes()); +} + +void rsSetElementAt(::rs_allocation a, const void *ptr, uint32_t x, + uint32_t y) { + rsSetElementAt(a, ptr, x, y, 0); +} + +void rsSetElementAt(::rs_allocation a, const void *ptr, uint32_t x) { + rsSetElementAt(a, ptr, x, 0, 0); +} + +const void *rsGetElementAt(::rs_allocation a, uint32_t x, uint32_t y, + uint32_t z) { + return ElementAt((Allocation *)a.p, RS_TYPE_UNSIGNED_8, 0, x, y, z); +} + +const void *rsGetElementAt(::rs_allocation a, uint32_t x, uint32_t y) { + return rsGetElementAt(a, x, y, 0); +} + +const void *rsGetElementAt(::rs_allocation a, uint32_t x) { + return rsGetElementAt(a, x, 0, 0); +} + +// Add NOLINT to suppress wrong warnings from clang-tidy. +#define ELEMENT_AT(T, DT, VS) \ + void rsSetElementAt_##T(::rs_allocation a, const T *val, uint32_t x, \ + uint32_t y, uint32_t z) { \ + void *r = ElementAt((Allocation *)a.p, DT, VS, x, y, z); \ + if (r != nullptr) \ + ((T *)r)[0] = *val; \ + else \ + ALOGE("Error from %s", __PRETTY_FUNCTION__); \ + } \ + void rsSetElementAt_##T(::rs_allocation a, const T *val, uint32_t x, \ + uint32_t y) { \ + rsSetElementAt_##T(a, val, x, y, 0); \ + } \ + void rsSetElementAt_##T(::rs_allocation a, const T *val, uint32_t x) { \ + rsSetElementAt_##T(a, val, x, 0, 0); \ + } \ + void rsGetElementAt_##T(::rs_allocation a, T *val, uint32_t x, uint32_t y, \ + uint32_t z) { /*NOLINT*/ \ + void *r = ElementAt((Allocation *)a.p, DT, VS, x, y, z); \ + if (r != nullptr) \ + *val = ((T *)r)[0]; \ + else \ + ALOGE("Error from %s", __PRETTY_FUNCTION__); \ + } \ + void rsGetElementAt_##T(::rs_allocation a, T *val, uint32_t x, \ + uint32_t y) { /*NOLINT*/ \ + rsGetElementAt_##T(a, val, x, y, 0); \ + } \ + void rsGetElementAt_##T(::rs_allocation a, T *val, uint32_t x) { /*NOLINT*/ \ + rsGetElementAt_##T(a, val, x, 0, 0); \ + } + +ELEMENT_AT(char, RS_TYPE_SIGNED_8, 1) +ELEMENT_AT(char2, RS_TYPE_SIGNED_8, 2) +ELEMENT_AT(char3, RS_TYPE_SIGNED_8, 3) +ELEMENT_AT(char4, RS_TYPE_SIGNED_8, 4) +ELEMENT_AT(uchar, RS_TYPE_UNSIGNED_8, 1) +ELEMENT_AT(uchar2, RS_TYPE_UNSIGNED_8, 2) +ELEMENT_AT(uchar3, RS_TYPE_UNSIGNED_8, 3) +ELEMENT_AT(uchar4, RS_TYPE_UNSIGNED_8, 4) +ELEMENT_AT(short, RS_TYPE_SIGNED_16, 1) +ELEMENT_AT(short2, RS_TYPE_SIGNED_16, 2) +ELEMENT_AT(short3, RS_TYPE_SIGNED_16, 3) +ELEMENT_AT(short4, RS_TYPE_SIGNED_16, 4) +ELEMENT_AT(ushort, RS_TYPE_UNSIGNED_16, 1) +ELEMENT_AT(ushort2, RS_TYPE_UNSIGNED_16, 2) +ELEMENT_AT(ushort3, RS_TYPE_UNSIGNED_16, 3) +ELEMENT_AT(ushort4, RS_TYPE_UNSIGNED_16, 4) +ELEMENT_AT(int, RS_TYPE_SIGNED_32, 1) +ELEMENT_AT(int2, RS_TYPE_SIGNED_32, 2) +ELEMENT_AT(int3, RS_TYPE_SIGNED_32, 3) +ELEMENT_AT(int4, RS_TYPE_SIGNED_32, 4) +ELEMENT_AT(uint, RS_TYPE_UNSIGNED_32, 1) +ELEMENT_AT(uint2, RS_TYPE_UNSIGNED_32, 2) +ELEMENT_AT(uint3, RS_TYPE_UNSIGNED_32, 3) +ELEMENT_AT(uint4, RS_TYPE_UNSIGNED_32, 4) +ELEMENT_AT(long, RS_TYPE_SIGNED_64, 1) +ELEMENT_AT(long2, RS_TYPE_SIGNED_64, 2) +ELEMENT_AT(long3, RS_TYPE_SIGNED_64, 3) +ELEMENT_AT(long4, RS_TYPE_SIGNED_64, 4) +ELEMENT_AT(ulong, RS_TYPE_UNSIGNED_64, 1) +ELEMENT_AT(ulong2, RS_TYPE_UNSIGNED_64, 2) +ELEMENT_AT(ulong3, RS_TYPE_UNSIGNED_64, 3) +ELEMENT_AT(ulong4, RS_TYPE_UNSIGNED_64, 4) +ELEMENT_AT(half, RS_TYPE_FLOAT_16, 1) +ELEMENT_AT(half2, RS_TYPE_FLOAT_16, 2) +ELEMENT_AT(half3, RS_TYPE_FLOAT_16, 3) +ELEMENT_AT(half4, RS_TYPE_FLOAT_16, 4) +ELEMENT_AT(float, RS_TYPE_FLOAT_32, 1) +ELEMENT_AT(float2, RS_TYPE_FLOAT_32, 2) +ELEMENT_AT(float3, RS_TYPE_FLOAT_32, 3) +ELEMENT_AT(float4, RS_TYPE_FLOAT_32, 4) +ELEMENT_AT(double, RS_TYPE_FLOAT_64, 1) +ELEMENT_AT(double2, RS_TYPE_FLOAT_64, 2) +ELEMENT_AT(double3, RS_TYPE_FLOAT_64, 3) +ELEMENT_AT(double4, RS_TYPE_FLOAT_64, 4) + +#undef ELEMENT_AT + +#ifndef __LP64__ +/* + * We miss some symbols for rs{Get,Set}Element_long,ulong variants because 64 + * bit integer values are 'long' in RS-land but might be 'long long' in the + * driver. Define native_long* and native_ulong* types to be vectors of + * 'long' as seen by the driver and define overloaded versions of + * rsSetElementAt_* and rsGetElementAt_*. This should get us the correct + * mangled names in the driver. + */ + +typedef long native_long2 __attribute__((ext_vector_type(2))); +typedef long native_long3 __attribute__((ext_vector_type(3))); +typedef long native_long4 __attribute__((ext_vector_type(4))); +typedef unsigned long native_ulong2 __attribute__((ext_vector_type(2))); +typedef unsigned long native_ulong3 __attribute__((ext_vector_type(3))); +typedef unsigned long native_ulong4 __attribute__((ext_vector_type(4))); + +// Add NOLINT to suppress wrong warnings from clang-tidy. +#define ELEMENT_AT_OVERLOADS(T, U) \ + void rsSetElementAt_##T(::rs_allocation a, const U *val, uint32_t x, \ + uint32_t y, uint32_t z) { \ + rsSetElementAt_##T(a, (T *)val, x, y, z); \ + } \ + void rsSetElementAt_##T(::rs_allocation a, const U *val, uint32_t x, \ + uint32_t y) { \ + rsSetElementAt_##T(a, (T *)val, x, y, 0); \ + } \ + void rsSetElementAt_##T(::rs_allocation a, const U *val, uint32_t x) { \ + rsSetElementAt_##T(a, (T *)val, x, 0, 0); \ + } \ + void rsGetElementAt_##T(::rs_allocation a, U *val, uint32_t x, uint32_t y, \ + uint32_t z) { /*NOLINT*/ \ + rsGetElementAt_##T(a, (T *)val, x, y, z); \ + } \ + void rsGetElementAt_##T(::rs_allocation a, U *val, uint32_t x, \ + uint32_t y) { /*NOLINT*/ \ + rsGetElementAt_##T(a, (T *)val, x, y, 0); \ + } \ + void rsGetElementAt_##T(::rs_allocation a, U *val, uint32_t x) { /*NOLINT*/ \ + rsGetElementAt_##T(a, (T *)val, x, 0, 0); \ + } + +ELEMENT_AT_OVERLOADS(long2, native_long2) +ELEMENT_AT_OVERLOADS(long3, native_long3) +ELEMENT_AT_OVERLOADS(long4, native_long4) +ELEMENT_AT_OVERLOADS(ulong, unsigned long) +ELEMENT_AT_OVERLOADS(ulong2, native_ulong2) +ELEMENT_AT_OVERLOADS(ulong3, native_ulong3) +ELEMENT_AT_OVERLOADS(ulong4, native_ulong4) + +// We also need variants of rs{Get,Set}ElementAt_long that take 'long long *' as +// we might have this overloaded variant in old APKs. +ELEMENT_AT_OVERLOADS(long, long long) + +#undef ELEMENT_AT_OVERLOADS +#endif + +////////////////////////////////////////////////////////////////////////////// +// ForEach routines +////////////////////////////////////////////////////////////////////////////// +void rsForEachInternal(int slot, rs_script_call *options, int hasOutput, + int numInputs, ::rs_allocation *allocs) { + Context *rsc = RsdCpuReference::getTlsContext(); + Script *s = const_cast<Script *>(RsdCpuReference::getTlsScript()); + if (numInputs > RS_KERNEL_MAX_ARGUMENTS) { + rsc->setError(RS_ERROR_BAD_SCRIPT, + "rsForEachInternal: too many inputs to a kernel."); + return; + } + Allocation *inputs[RS_KERNEL_MAX_ARGUMENTS]; + for (int i = 0; i < numInputs; i++) { + inputs[i] = (Allocation *)allocs[i].p; + } + Allocation *out = hasOutput ? (Allocation *)allocs[numInputs].p : nullptr; + rsrForEach(rsc, s, slot, numInputs, numInputs > 0 ? inputs : nullptr, out, + nullptr, 0, (RsScriptCall *)options); +} + +void __attribute__((overloadable)) +rsForEach(::rs_script script, ::rs_allocation in, ::rs_allocation out, + const void *usr, const rs_script_call *call) { + Context *rsc = RsdCpuReference::getTlsContext(); + rsrForEach(rsc, (Script *)script.p, 0, 1, (Allocation **)&in.p, + (Allocation *)out.p, usr, 0, (RsScriptCall *)call); +} + +void __attribute__((overloadable)) +rsForEach(::rs_script script, ::rs_allocation in, ::rs_allocation out, + const void *usr) { + Context *rsc = RsdCpuReference::getTlsContext(); + rsrForEach(rsc, (Script *)script.p, 0, 1, (Allocation **)&in.p, + (Allocation *)out.p, usr, 0, nullptr); +} + +void __attribute__((overloadable)) +rsForEach(::rs_script script, ::rs_allocation in, ::rs_allocation out) { + Context *rsc = RsdCpuReference::getTlsContext(); + rsrForEach(rsc, (Script *)script.p, 0, 1, (Allocation **)&in.p, + (Allocation *)out.p, nullptr, 0, nullptr); +} + +// These functions are only supported in 32-bit. +#ifndef __LP64__ +void __attribute__((overloadable)) +rsForEach(::rs_script script, ::rs_allocation in, ::rs_allocation out, + const void *usr, uint32_t usrLen) { + Context *rsc = RsdCpuReference::getTlsContext(); + rsrForEach(rsc, (Script *)script.p, 0, 1, (Allocation **)&in.p, + (Allocation *)out.p, usr, usrLen, nullptr); +} + +void __attribute__((overloadable)) +rsForEach(::rs_script script, ::rs_allocation in, ::rs_allocation out, + const void *usr, uint32_t usrLen, const rs_script_call *call) { + Context *rsc = RsdCpuReference::getTlsContext(); + rsrForEach(rsc, (Script *)script.p, 0, 1, (Allocation **)&in.p, + (Allocation *)out.p, usr, usrLen, (RsScriptCall *)call); +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// Message routines +////////////////////////////////////////////////////////////////////////////// +uint32_t rsSendToClient(int cmdID) { + Context *rsc = RsdCpuReference::getTlsContext(); + return rsrToClient(rsc, cmdID, (const void *)nullptr, 0); +} + +uint32_t rsSendToClient(int cmdID, const void *data, uint32_t len) { + Context *rsc = RsdCpuReference::getTlsContext(); + return rsrToClient(rsc, cmdID, data, len); +} + +uint32_t rsSendToClientBlocking(int cmdID) { + Context *rsc = RsdCpuReference::getTlsContext(); + return rsrToClientBlocking(rsc, cmdID, (const void *)nullptr, 0); +} + +uint32_t rsSendToClientBlocking(int cmdID, const void *data, uint32_t len) { + Context *rsc = RsdCpuReference::getTlsContext(); + return rsrToClientBlocking(rsc, cmdID, data, len); +} + +////////////////////////////////////////////////////////////////////////////// +// Time routines +////////////////////////////////////////////////////////////////////////////// + +// time_t is int in 32-bit RenderScript. time_t is long in bionic. rsTime and +// rsLocaltime are set to explicitly take 'const int *' so we generate the +// correct mangled names. +#ifndef __LP64__ +int rsTime(int *timer) { +#else +time_t rsTime(time_t *timer) { +#endif + Context *rsc = RsdCpuReference::getTlsContext(); + return rsrTime(rsc, (time_t *)timer); +} + +#ifndef __LP64__ +rs_tm *rsLocaltime(rs_tm *local, const int *timer) { +#else +rs_tm *rsLocaltime(rs_tm *local, const time_t *timer) { +#endif + Context *rsc = RsdCpuReference::getTlsContext(); + return (rs_tm *)rsrLocalTime(rsc, (tm *)local, (time_t *)timer); +} + +int64_t rsUptimeMillis() { + Context *rsc = RsdCpuReference::getTlsContext(); + return rsrUptimeMillis(rsc); +} + +int64_t rsUptimeNanos() { + Context *rsc = RsdCpuReference::getTlsContext(); + return rsrUptimeNanos(rsc); +} + +float rsGetDt() { + Context *rsc = RsdCpuReference::getTlsContext(); + const Script *sc = RsdCpuReference::getTlsScript(); + return rsrGetDt(rsc, sc); +} + +////////////////////////////////////////////////////////////////////////////// +// Debug routines +////////////////////////////////////////////////////////////////////////////// +void rsDebug(const char *s, float f) { + ALOGD("%s %f, 0x%08x", s, f, *((int *)(&f))); +} + +void rsDebug(const char *s, float f1, float f2) { + ALOGD("%s {%f, %f}", s, f1, f2); +} + +void rsDebug(const char *s, float f1, float f2, float f3) { + ALOGD("%s {%f, %f, %f}", s, f1, f2, f3); +} + +void rsDebug(const char *s, float f1, float f2, float f3, float f4) { + ALOGD("%s {%f, %f, %f, %f}", s, f1, f2, f3, f4); +} + +void rsDebug(const char *s, const float2 *f2) { + float2 f = *f2; + ALOGD("%s {%f, %f}", s, f.x, f.y); +} + +void rsDebug(const char *s, const float3 *f3) { + float3 f = *f3; + ALOGD("%s {%f, %f, %f}", s, f.x, f.y, f.z); +} + +void rsDebug(const char *s, const float4 *f4) { + float4 f = *f4; + ALOGD("%s {%f, %f, %f, %f}", s, f.x, f.y, f.z, f.w); +} + +// Accept a half value converted to float. This eliminates the need in the +// driver to properly support the half datatype (either by adding compiler flags +// for half or link against compiler_rt). +void rsDebug(const char *s, float f, ushort us) { + ALOGD("%s {%f} {0x%hx}", s, f, us); +} + +void rsDebug(const char *s, const float2 *f2, const ushort2 *us2) { + float2 f = *f2; + ushort2 us = *us2; + ALOGD("%s {%f %f} {0x%hx 0x%hx}", s, f.x, f.y, us.x, us.y); +} + +void rsDebug(const char *s, const float3 *f3, const ushort3 *us3) { + float3 f = *f3; + ushort3 us = *us3; + ALOGD("%s {%f %f %f} {0x%hx 0x%hx 0x%hx}", s, f.x, f.y, f.z, us.x, us.y, + us.z); +} + +void rsDebug(const char *s, const float4 *f4, const ushort4 *us4) { + float4 f = *f4; + ushort4 us = *us4; + ALOGD("%s {%f %f %f %f} {0x%hx 0x%hx 0x%hx 0x%hx}", s, f.x, f.y, f.z, f.w, + us.x, us.y, us.z, us.w); +} + +void rsDebug(const char *s, double d) { + ALOGD("%s %f, 0x%08llx", s, d, *((long long *)(&d))); +} + +void rsDebug(const char *s, const double2 *d2) { + double2 d = *d2; + ALOGD("%s {%f, %f}", s, d.x, d.y); +} + +void rsDebug(const char *s, const double3 *d3) { + double3 d = *d3; + ALOGD("%s {%f, %f, %f}", s, d.x, d.y, d.z); +} + +void rsDebug(const char *s, const double4 *d4) { + double4 d = *d4; + ALOGD("%s {%f, %f, %f, %f}", s, d.x, d.y, d.z, d.w); +} + +void rsDebug(const char *s, const rs_matrix4x4 *m) { + float *f = (float *)m; + ALOGD("%s {%f, %f, %f, %f", s, f[0], f[4], f[8], f[12]); + ALOGD("%s %f, %f, %f, %f", s, f[1], f[5], f[9], f[13]); + ALOGD("%s %f, %f, %f, %f", s, f[2], f[6], f[10], f[14]); + ALOGD("%s %f, %f, %f, %f}", s, f[3], f[7], f[11], f[15]); +} + +void rsDebug(const char *s, const rs_matrix3x3 *m) { + float *f = (float *)m; + ALOGD("%s {%f, %f, %f", s, f[0], f[3], f[6]); + ALOGD("%s %f, %f, %f", s, f[1], f[4], f[7]); + ALOGD("%s %f, %f, %f}", s, f[2], f[5], f[8]); +} + +void rsDebug(const char *s, const rs_matrix2x2 *m) { + float *f = (float *)m; + ALOGD("%s {%f, %f", s, f[0], f[2]); + ALOGD("%s %f, %f}", s, f[1], f[3]); +} + +void rsDebug(const char *s, char c) { + ALOGD("%s %hhd 0x%hhx", s, c, (unsigned char)c); +} + +void rsDebug(const char *s, const char2 *c2) { + char2 c = *c2; + ALOGD("%s {%hhd, %hhd} 0x%hhx 0x%hhx", s, c.x, c.y, (unsigned char)c.x, + (unsigned char)c.y); +} + +void rsDebug(const char *s, const char3 *c3) { + char3 c = *c3; + ALOGD("%s {%hhd, %hhd, %hhd} 0x%hhx 0x%hhx 0x%hhx", s, c.x, c.y, c.z, + (unsigned char)c.x, (unsigned char)c.y, (unsigned char)c.z); +} + +void rsDebug(const char *s, const char4 *c4) { + char4 c = *c4; + ALOGD("%s {%hhd, %hhd, %hhd, %hhd} 0x%hhx 0x%hhx 0x%hhx 0x%hhx", s, c.x, c.y, + c.z, c.w, (unsigned char)c.x, (unsigned char)c.y, (unsigned char)c.z, + (unsigned char)c.w); +} + +void rsDebug(const char *s, unsigned char c) { + ALOGD("%s %hhu 0x%hhx", s, c, c); +} + +void rsDebug(const char *s, const uchar2 *c2) { + uchar2 c = *c2; + ALOGD("%s {%hhu, %hhu} 0x%hhx 0x%hhx", s, c.x, c.y, c.x, c.y); +} + +void rsDebug(const char *s, const uchar3 *c3) { + uchar3 c = *c3; + ALOGD("%s {%hhu, %hhu, %hhu} 0x%hhx 0x%hhx 0x%hhx", s, c.x, c.y, c.z, c.x, + c.y, c.z); +} + +void rsDebug(const char *s, const uchar4 *c4) { + uchar4 c = *c4; + ALOGD("%s {%hhu, %hhu, %hhu, %hhu} 0x%hhx 0x%hhx 0x%hhx 0x%hhx", s, c.x, c.y, + c.z, c.w, c.x, c.y, c.z, c.w); +} + +void rsDebug(const char *s, short c) { ALOGD("%s %hd 0x%hx", s, c, c); } + +void rsDebug(const char *s, const short2 *c2) { + short2 c = *c2; + ALOGD("%s {%hd, %hd} 0x%hx 0x%hx", s, c.x, c.y, c.x, c.y); +} + +void rsDebug(const char *s, const short3 *c3) { + short3 c = *c3; + ALOGD("%s {%hd, %hd, %hd} 0x%hx 0x%hx 0x%hx", s, c.x, c.y, c.z, c.x, c.y, + c.z); +} + +void rsDebug(const char *s, const short4 *c4) { + short4 c = *c4; + ALOGD("%s {%hd, %hd, %hd, %hd} 0x%hx 0x%hx 0x%hx 0x%hx", s, c.x, c.y, c.z, + c.w, c.x, c.y, c.z, c.w); +} + +void rsDebug(const char *s, unsigned short c) { + ALOGD("%s %hu 0x%hx", s, c, c); +} + +void rsDebug(const char *s, const ushort2 *c2) { + ushort2 c = *c2; + ALOGD("%s {%hu, %hu} 0x%hx 0x%hx", s, c.x, c.y, c.x, c.y); +} + +void rsDebug(const char *s, const ushort3 *c3) { + ushort3 c = *c3; + ALOGD("%s {%hu, %hu, %hu} 0x%hx 0x%hx 0x%hx", s, c.x, c.y, c.z, c.x, c.y, + c.z); +} + +void rsDebug(const char *s, const ushort4 *c4) { + ushort4 c = *c4; + ALOGD("%s {%hu, %hu, %hu, %hu} 0x%hx 0x%hx 0x%hx 0x%hx", s, c.x, c.y, c.z, + c.w, c.x, c.y, c.z, c.w); +} + +void rsDebug(const char *s, int i) { ALOGD("%s %d 0x%x", s, i, i); } + +void rsDebug(const char *s, const int2 *i2) { + int2 i = *i2; + ALOGD("%s {%d, %d} 0x%x 0x%x", s, i.x, i.y, i.x, i.y); +} + +void rsDebug(const char *s, const int3 *i3) { + int3 i = *i3; + ALOGD("%s {%d, %d, %d} 0x%x 0x%x 0x%x", s, i.x, i.y, i.z, i.x, i.y, i.z); +} + +void rsDebug(const char *s, const int4 *i4) { + int4 i = *i4; + ALOGD("%s {%d, %d, %d, %d} 0x%x 0x%x 0x%x 0x%x", s, i.x, i.y, i.z, i.w, i.x, + i.y, i.z, i.w); +} + +void rsDebug(const char *s, unsigned int i) { ALOGD("%s %u 0x%x", s, i, i); } + +void rsDebug(const char *s, const uint2 *i2) { + uint2 i = *i2; + ALOGD("%s {%u, %u} 0x%x 0x%x", s, i.x, i.y, i.x, i.y); +} + +void rsDebug(const char *s, const uint3 *i3) { + uint3 i = *i3; + ALOGD("%s {%u, %u, %u} 0x%x 0x%x 0x%x", s, i.x, i.y, i.z, i.x, i.y, i.z); +} + +void rsDebug(const char *s, const uint4 *i4) { + uint4 i = *i4; + ALOGD("%s {%u, %u, %u, %u} 0x%x 0x%x 0x%x 0x%x", s, i.x, i.y, i.z, i.w, i.x, + i.y, i.z, i.w); +} + +template <typename T> +static inline long long LL(const T &x) { + return static_cast<long long>(x); +} + +template <typename T> +static inline unsigned long long LLu(const T &x) { + return static_cast<unsigned long long>(x); +} + +void rsDebug(const char *s, long l) { + ALOGD("%s %lld 0x%llx", s, LL(l), LL(l)); +} + +void rsDebug(const char *s, long long ll) { + ALOGD("%s %lld 0x%llx", s, LL(ll), LL(ll)); +} + +void rsDebug(const char *s, const long2 *c) { + long2 ll = *c; + ALOGD("%s {%lld, %lld} 0x%llx 0x%llx", s, LL(ll.x), LL(ll.y), LL(ll.x), + LL(ll.y)); +} + +void rsDebug(const char *s, const long3 *c) { + long3 ll = *c; + ALOGD("%s {%lld, %lld, %lld} 0x%llx 0x%llx 0x%llx", s, LL(ll.x), LL(ll.y), + LL(ll.z), LL(ll.x), LL(ll.y), LL(ll.z)); +} + +void rsDebug(const char *s, const long4 *c) { + long4 ll = *c; + ALOGD("%s {%lld, %lld, %lld, %lld} 0x%llx 0x%llx 0x%llx 0x%llx", s, LL(ll.x), + LL(ll.y), LL(ll.z), LL(ll.w), LL(ll.x), LL(ll.y), LL(ll.z), LL(ll.w)); +} + +void rsDebug(const char *s, unsigned long l) { + unsigned long long ll = l; + ALOGD("%s %llu 0x%llx", s, ll, ll); +} + +void rsDebug(const char *s, unsigned long long ll) { + ALOGD("%s %llu 0x%llx", s, ll, ll); +} + +void rsDebug(const char *s, const ulong2 *c) { + ulong2 ll = *c; + ALOGD("%s {%llu, %llu} 0x%llx 0x%llx", s, LLu(ll.x), LLu(ll.y), LLu(ll.x), + LLu(ll.y)); +} + +void rsDebug(const char *s, const ulong3 *c) { + ulong3 ll = *c; + ALOGD("%s {%llu, %llu, %llu} 0x%llx 0x%llx 0x%llx", s, LLu(ll.x), LLu(ll.y), + LLu(ll.z), LLu(ll.x), LLu(ll.y), LLu(ll.z)); +} + +void rsDebug(const char *s, const ulong4 *c) { + ulong4 ll = *c; + ALOGD("%s {%llu, %llu, %llu, %llu} 0x%llx 0x%llx 0x%llx 0x%llx", s, + LLu(ll.x), LLu(ll.y), LLu(ll.z), LLu(ll.w), LLu(ll.x), LLu(ll.y), + LLu(ll.z), LLu(ll.w)); +} + +// FIXME: We need to export these function signatures for the compatibility +// library. The C++ name mangling that LLVM uses for ext_vector_type requires +// different versions for "long" vs. "long long". Note that the called +// functions are still using the appropriate 64-bit sizes. + +#ifndef __LP64__ +typedef long l2 __attribute__((ext_vector_type(2))); +typedef long l3 __attribute__((ext_vector_type(3))); +typedef long l4 __attribute__((ext_vector_type(4))); +typedef unsigned long ul2 __attribute__((ext_vector_type(2))); +typedef unsigned long ul3 __attribute__((ext_vector_type(3))); +typedef unsigned long ul4 __attribute__((ext_vector_type(4))); + +void rsDebug(const char *s, const l2 *c) { + long2 ll = *(const long2 *)c; + ALOGD("%s {%lld, %lld} 0x%llx 0x%llx", s, LL(ll.x), LL(ll.y), LL(ll.x), + LL(ll.y)); +} + +void rsDebug(const char *s, const l3 *c) { + long3 ll = *(const long3 *)c; + ALOGD("%s {%lld, %lld, %lld} 0x%llx 0x%llx 0x%llx", s, LL(ll.x), LL(ll.y), + LL(ll.z), LL(ll.x), LL(ll.y), LL(ll.z)); +} + +void rsDebug(const char *s, const l4 *c) { + long4 ll = *(const long4 *)c; + ALOGD("%s {%lld, %lld, %lld, %lld} 0x%llx 0x%llx 0x%llx 0x%llx", s, LL(ll.x), + LL(ll.y), LL(ll.z), LL(ll.w), LL(ll.x), LL(ll.y), LL(ll.z), LL(ll.w)); +} + +void rsDebug(const char *s, const ul2 *c) { + ulong2 ll = *(const ulong2 *)c; + ALOGD("%s {%llu, %llu} 0x%llx 0x%llx", s, LLu(ll.x), LLu(ll.y), LLu(ll.x), + LLu(ll.y)); +} + +void rsDebug(const char *s, const ul3 *c) { + ulong3 ll = *(const ulong3 *)c; + ALOGD("%s {%llu, %llu, %llu} 0x%llx 0x%llx 0x%llx", s, LLu(ll.x), LLu(ll.y), + LLu(ll.z), LLu(ll.x), LLu(ll.y), LLu(ll.z)); +} + +void rsDebug(const char *s, const ul4 *c) { + ulong4 ll = *(const ulong4 *)c; + ALOGD("%s {%llu, %llu, %llu, %llu} 0x%llx 0x%llx 0x%llx 0x%llx", s, + LLu(ll.x), LLu(ll.y), LLu(ll.z), LLu(ll.w), LLu(ll.x), LLu(ll.y), + LLu(ll.z), LLu(ll.w)); +} +#endif + +void rsDebug(const char *s, const long2 ll) { + ALOGD("%s {%lld, %lld} 0x%llx 0x%llx", s, LL(ll.x), LL(ll.y), LL(ll.x), + LL(ll.y)); +} + +void rsDebug(const char *s, const long3 ll) { + ALOGD("%s {%lld, %lld, %lld} 0x%llx 0x%llx 0x%llx", s, LL(ll.x), LL(ll.y), + LL(ll.z), LL(ll.x), LL(ll.y), LL(ll.z)); +} + +void rsDebug(const char *s, const long4 ll) { + ALOGD("%s {%lld, %lld, %lld, %lld} 0x%llx 0x%llx 0x%llx 0x%llx", s, LL(ll.x), + LL(ll.y), LL(ll.z), LL(ll.w), LL(ll.x), LL(ll.y), LL(ll.z), LL(ll.w)); +} + +void rsDebug(const char *s, const ulong2 ll) { + ALOGD("%s {%llu, %llu} 0x%llx 0x%llx", s, LLu(ll.x), LLu(ll.y), LLu(ll.x), + LLu(ll.y)); +} + +void rsDebug(const char *s, const ulong3 ll) { + ALOGD("%s {%llu, %llu, %llu} 0x%llx 0x%llx 0x%llx", s, LLu(ll.x), LLu(ll.y), + LLu(ll.z), LLu(ll.x), LLu(ll.y), LLu(ll.z)); +} + +void rsDebug(const char *s, const ulong4 ll) { + ALOGD("%s {%llu, %llu, %llu, %llu} 0x%llx 0x%llx 0x%llx 0x%llx", s, + LLu(ll.x), LLu(ll.y), LLu(ll.z), LLu(ll.w), LLu(ll.x), LLu(ll.y), + LLu(ll.z), LLu(ll.w)); +} + +void rsDebug(const char *s, const void *p) { ALOGD("%s %p", s, p); } diff --git a/rsov/driver/rsovSampler.cpp b/rsov/driver/rsovSampler.cpp new file mode 100644 index 00000000..0857c6ee --- /dev/null +++ b/rsov/driver/rsovSampler.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rsovSampler.h" + +#include "rsContext.h" + +using android::renderscript::Context; +using android::renderscript::Sampler; +using android::renderscript::rs_sampler; + +bool rsovSamplerInit(const Context *rsc, const Sampler *s) { return true; } + +void rsovSamplerDestroy(const Context *rsc, const Sampler *s) {} + +void rsovSamplerUpdateCachedObject(const Context *rsc, const Sampler *alloc, + rs_sampler *obj) { + obj->p = alloc; +#ifdef __LP64__ + obj->r = nullptr; + if (alloc != nullptr) { + obj->v1 = alloc->mHal.drv; + } else { + obj->v1 = nullptr; + } + obj->v2 = nullptr; +#endif +} diff --git a/rsov/driver/rsovSampler.h b/rsov/driver/rsovSampler.h new file mode 100644 index 00000000..9b8112ca --- /dev/null +++ b/rsov/driver/rsovSampler.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RSOV_SAMPLER_H +#define RSOV_SAMPLER_H + +#include "rs_hal.h" + +extern bool rsovSamplerInit(const android::renderscript::Context *rsc, + const android::renderscript::Sampler *); + +extern void rsovSamplerDestroy(const android::renderscript::Context *rsc, + const android::renderscript::Sampler *); + +extern void rsovSamplerUpdateCachedObject( + const android::renderscript::Context *rsc, + const android::renderscript::Sampler *, + android::renderscript::rs_sampler *obj); + +#endif // RSD_SAMPLER_H diff --git a/rsov/driver/rsovScript.cpp b/rsov/driver/rsovScript.cpp new file mode 100644 index 00000000..2d0fa250 --- /dev/null +++ b/rsov/driver/rsovScript.cpp @@ -0,0 +1,675 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rsovScript.h" + +#include <fstream> + +#include "rsContext.h" +#include "rsType.h" +#include "rsUtils.h" +#include "rsovAllocation.h" +#include "rsovContext.h" +#include "rsovCore.h" + +namespace android { +namespace renderscript { +namespace rsov { + +namespace { + +const char *COMPILER_EXE_PATH = "/system/bin/bcc_rsov"; + +std::vector<const char *> setCompilerArgs(const char *bcFileName, + const char *cacheDir) { + rsAssert(bcFileName && cacheDir); + + std::vector<const char *> args; + + args.push_back(COMPILER_EXE_PATH); + args.push_back(bcFileName); + + args.push_back(nullptr); + return args; +} + +void writeBytes(const char *filename, const char *bytes, size_t size) { + std::ofstream ofs(filename, std::ios::binary); + ofs.write(bytes, size); + ofs.close(); +} + +std::vector<uint32_t> readWords(const char *filename) { + std::ifstream ifs(filename, std::ios::binary); + + ifs.seekg(0, ifs.end); + int length = ifs.tellg(); + ifs.seekg(0, ifs.beg); + + rsAssert(((length & 3) == 0) && "File size expected to be multiples of 4"); + + std::vector<uint32_t> spvWords(length / sizeof(uint32_t)); + + ifs.read((char *)(spvWords.data()), length); + + ifs.close(); + + return spvWords; +} + +std::vector<uint32_t> compileBitcode(const char *resName, const char *cacheDir, + const char *bitcode, size_t bitcodeSize) { + rsAssert(bitcode && bitcodeSize); + + // TODO: Cache the generated code + + std::string bcFileName(cacheDir); + bcFileName.append("/"); + bcFileName.append(resName); + bcFileName.append(".bc"); + + writeBytes(bcFileName.c_str(), bitcode, bitcodeSize); + + auto args = setCompilerArgs(bcFileName.c_str(), cacheDir); + + if (!rsuExecuteCommand(COMPILER_EXE_PATH, args.size() - 1, args.data())) { + ALOGE("compiler command line failed"); + return std::vector<uint32_t>(); + } + + ALOGV("compiler command line succeeded"); + + std::string spvFileName(cacheDir); + spvFileName.append("/"); + spvFileName.append(resName); + spvFileName.append(".spv"); + + return readWords(spvFileName.c_str()); +} + +} // anonymous namespace + +RSoVScript::RSoVScript(RSoVContext *context, std::vector<uint32_t> &&spvWords) + : mRSoV(context), + mDevice(context->getDevice()), + mSPIRVWords(std::move(spvWords)) {} + +RSoVScript::~RSoVScript() { + delete mCpuScript; + // TODO: destroy shader +} + +void RSoVScript::populateScript(Script *) { + // TODO: implement this +} + +void RSoVScript::invokeFunction(uint32_t slot, const void *params, + size_t paramLength) { + // TODO: implement this +} + +int RSoVScript::invokeRoot() { + // TODO: implement this + return 0; +} + +void RSoVScript::invokeForEach(uint32_t slot, const Allocation **ains, + uint32_t inLen, Allocation *aout, + const void *usr, uint32_t usrLen, + const RsScriptCall *sc) { + // TODO: Handle kernel without input Allocation + // TODO: Handle multi-input kernel + rsAssert(ains && inLen == 1); + + RSoVAllocation *inputAllocation = + static_cast<RSoVAllocation *>(ains[0]->mHal.drv); + RSoVAllocation *outputAllocation = + static_cast<RSoVAllocation *>(aout->mHal.drv); + runForEach(inputAllocation, outputAllocation); +} + +void RSoVScript::invokeReduce(uint32_t slot, const Allocation **ains, + uint32_t inLen, Allocation *aout, + const RsScriptCall *sc) { + // TODO: implement this +} + +void RSoVScript::invokeInit() { + // TODO: implement this +} + +void RSoVScript::invokeFreeChildren() { + // TODO: implement this +} + +void RSoVScript::setGlobalVar(uint32_t slot, const void *data, + size_t dataLength) { + // TODO: implement this +} + +void RSoVScript::getGlobalVar(uint32_t slot, void *data, size_t dataLength) { + // TODO: implement this +} + +void RSoVScript::setGlobalVarWithElemDims(uint32_t slot, const void *data, + size_t dataLength, const Element *e, + const uint32_t *dims, + size_t dimLength) { + // TODO: implement this +} + +void RSoVScript::setGlobalBind(uint32_t slot, Allocation *data) { + // TODO: implement this +} + +void RSoVScript::setGlobalObj(uint32_t slot, ObjectBase *obj) { + // TODO: implement this +} + +Allocation *RSoVScript::getAllocationForPointer(const void *ptr) const { + // TODO: implement this + return nullptr; +} + +int RSoVScript::getGlobalEntries() const { + // TODO: implement this + return 0; +} + +const char *RSoVScript::getGlobalName(int i) const { + // TODO: implement this + return nullptr; +} + +const void *RSoVScript::getGlobalAddress(int i) const { + // TODO: implement this + return nullptr; +} + +size_t RSoVScript::getGlobalSize(int i) const { + // TODO: implement this + return 0; +} + +uint32_t RSoVScript::getGlobalProperties(int i) const { + // TODO: implement this + return 0; +} + +void RSoVScript::InitDescriptorAndPipelineLayouts() { + VkDescriptorSetLayoutBinding layout_bindings[] = { + { + // In the current implementation, these are all STORAGE_IMAGEs + // TODO: + // 1) replace all images with buffers + // 2) based on usage, select either images or buffers + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + .pImmutableSamplers = nullptr, + }, + { + .binding = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + .pImmutableSamplers = nullptr, + }, +#ifdef SUPPORT_GLOBAL_VARIABLES + { + .binding = 2, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + .pImmutableSamplers = nullptr, + } +#endif + }; + + VkDescriptorSetLayoutCreateInfo descriptor_layout = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .bindingCount = NELEM(layout_bindings), + .pBindings = layout_bindings, + }; + + VkResult res; + + mDescLayout.resize(NUM_DESCRIPTOR_SETS); + res = vkCreateDescriptorSetLayout(mDevice, &descriptor_layout, NULL, + mDescLayout.data()); + if (res != VK_SUCCESS) { + __android_log_print(ANDROID_LOG_ERROR, "ComputeTest", + "vkCreateDescriptorSetLayout() returns %d", res); + } + rsAssert(res == VK_SUCCESS); + /* + VkPushConstantRange pushConstantRange[] = { { + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + .offset = 0, + .size = 16 + } }; + */ + /* Now use the descriptor layout to create a pipeline layout */ + VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .pushConstantRangeCount = 0, + .pPushConstantRanges = nullptr, + .setLayoutCount = NUM_DESCRIPTOR_SETS, + .pSetLayouts = mDescLayout.data(), + }; + + res = vkCreatePipelineLayout(mDevice, &pPipelineLayoutCreateInfo, NULL, + &mPipelineLayout); + rsAssert(res == VK_SUCCESS); + + ALOGV("%s succeeded.", __FUNCTION__); +} + +void RSoVScript::InitShader() { + VkResult res; + + mShaderStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + mShaderStage.pNext = nullptr; + mShaderStage.pSpecializationInfo = nullptr; + mShaderStage.flags = 0; + mShaderStage.stage = VK_SHADER_STAGE_COMPUTE_BIT; + mShaderStage.pName = "main"; + + VkShaderModuleCreateInfo moduleCreateInfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .codeSize = mSPIRVWords.size() * sizeof(unsigned int), + .pCode = mSPIRVWords.data(), + }; + res = vkCreateShaderModule(mDevice, &moduleCreateInfo, NULL, + &mShaderStage.module); + rsAssert(res == VK_SUCCESS); + + ALOGV("%s succeeded.", __FUNCTION__); +} + +void RSoVScript::InitDescriptorPool() { + /* DEPENDS on InitDescriptorAndPipelineLayouts() */ + + VkResult res; + VkDescriptorPoolSize type_count[] = { + // The current implementation uses STORAGE_IMAGE for all allocations + { + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, .descriptorCount = 1, + }, + { + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, .descriptorCount = 1, + }, +#ifdef SUPPORT_GLOBAL_VARIABLES + { + .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorCount = 1, + } +#endif + }; + + VkDescriptorPoolCreateInfo descriptor_pool = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .pNext = nullptr, + .maxSets = 1, + .poolSizeCount = NELEM(type_count), + .pPoolSizes = type_count, + }; + + res = vkCreateDescriptorPool(mDevice, &descriptor_pool, NULL, &mDescPool); + rsAssert(res == VK_SUCCESS); + + ALOGV("%s succeeded.", __FUNCTION__); +} + +void RSoVScript::InitDescriptorSet(const RSoVAllocation *inputAllocation, + RSoVAllocation *outputAllocation) { + VkResult res; + + VkDescriptorSetAllocateInfo alloc_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .pNext = NULL, + .descriptorPool = mDescPool, + .descriptorSetCount = NUM_DESCRIPTOR_SETS, + .pSetLayouts = mDescLayout.data(), + }; + + mDescSet.resize(NUM_DESCRIPTOR_SETS); + res = vkAllocateDescriptorSets(mDevice, &alloc_info, mDescSet.data()); + rsAssert(res == VK_SUCCESS); + + const VkWriteDescriptorSet writes[] = { + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = mDescSet[0], + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .pImageInfo = inputAllocation->getImageInfo(), + }, + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = mDescSet[0], + .dstBinding = 1, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .pImageInfo = outputAllocation->getImageInfo(), + }, +#ifdef SUPPORT_GLOBAL_VARIABLES + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = mDescSet[0], + .dstBinding = 2, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .pBufferInfo = somebuffer_info, + }, +#endif + }; + + vkUpdateDescriptorSets(mDevice, NELEM(writes), writes, 0, NULL); + + ALOGV("%s succeeded.", __FUNCTION__); +} + +void RSoVScript::InitPipeline() { + // DEPENDS on mShaderStage, i.e., InitShader() + + VkResult res; + + VkComputePipelineCreateInfo pipeline_info = { + .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + .pNext = nullptr, + .layout = mPipelineLayout, + .basePipelineHandle = VK_NULL_HANDLE, + .basePipelineIndex = 0, + .flags = 0, + .stage = mShaderStage, + }; + res = vkCreateComputePipelines(mDevice, VK_NULL_HANDLE, 1, &pipeline_info, + NULL, &mComputePipeline); + rsAssert(res == VK_SUCCESS); + + ALOGV("%s succeeded.", __FUNCTION__); +} + +void RSoVScript::runForEach(const RSoVAllocation *inputAllocation, + RSoVAllocation *outputAllocation) { + VkResult res; + + InitDescriptorAndPipelineLayouts(); + InitShader(); + InitDescriptorPool(); + InitDescriptorSet(inputAllocation, outputAllocation); + // InitPipelineCache(); + InitPipeline(); + + VkCommandBuffer cmd; + + VkCommandBufferAllocateInfo cmd_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .pNext = nullptr, + .commandPool = mRSoV->getCmdPool(), + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1, + }; + + res = vkAllocateCommandBuffers(mDevice, &cmd_info, &cmd); + rsAssert(res == VK_SUCCESS); + + VkCommandBufferBeginInfo cmd_buf_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .pNext = nullptr, + .flags = 0, + .pInheritanceInfo = nullptr, + }; + + res = vkBeginCommandBuffer(cmd, &cmd_buf_info); + rsAssert(res == VK_SUCCESS); + + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, mComputePipeline); + + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, mPipelineLayout, + 0, mDescSet.size(), mDescSet.data(), 0, nullptr); + + const uint32_t width = inputAllocation->getWidth(); + const uint32_t height = rsMax(inputAllocation->getHeight(), 1U); + const uint32_t depth = rsMax(inputAllocation->getDepth(), 1U); + vkCmdDispatch(cmd, width, height, depth); + + res = vkEndCommandBuffer(cmd); + assert(res == VK_SUCCESS); + + VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .commandBufferCount = 1, + .pCommandBuffers = &cmd, + }; + + VkFence fence; + + VkFenceCreateInfo fenceInfo = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + }; + + vkCreateFence(mDevice, &fenceInfo, NULL, &fence); + + vkQueueSubmit(mRSoV->getQueue(), 1, &submit_info, fence); + + // Make sure command buffer is finished + do { + res = vkWaitForFences(mDevice, 1, &fence, VK_TRUE, 100000); + } while (res == VK_TIMEOUT); + + rsAssert(res == VK_SUCCESS); + + vkDestroyFence(mDevice, fence, NULL); + + // TODO: shall we reuse command buffers? + VkCommandBuffer cmd_bufs[] = {cmd}; + vkFreeCommandBuffers(mDevice, mRSoV->getCmdPool(), 1, cmd_bufs); + + vkDestroyPipeline(mDevice, mComputePipeline, nullptr); + for (int i = 0; i < NUM_DESCRIPTOR_SETS; i++) + vkDestroyDescriptorSetLayout(mDevice, mDescLayout[i], nullptr); + vkDestroyPipelineLayout(mDevice, mPipelineLayout, nullptr); + vkDestroyDescriptorPool(mDevice, mDescPool, nullptr); + vkDestroyShaderModule(mDevice, mShaderStage.module, nullptr); + + ALOGV("%s succeeded.", __FUNCTION__); +} + +} // namespace rsov +} // namespace renderscript +} // namespace android + +using android::renderscript::Allocation; +using android::renderscript::Context; +using android::renderscript::Element; +using android::renderscript::ObjectBase; +using android::renderscript::RsdCpuReference; +using android::renderscript::Script; +using android::renderscript::ScriptC; +using android::renderscript::rs_script; +using android::renderscript::rsov::RSoVContext; +using android::renderscript::rsov::RSoVScript; +using android::renderscript::rsov::compileBitcode; + +bool rsovScriptInit(const Context *rsc, ScriptC *script, char const *resName, + char const *cacheDir, uint8_t const *bitcode, + size_t bitcodeSize, uint32_t flags) { + std::vector<uint32_t> &&spvWords = + compileBitcode(resName, cacheDir, (const char *)bitcode, bitcodeSize); + + if (spvWords.empty()) { + ALOGE("compilation failed for script %s", resName); + return false; + } + + RSoVHal *hal = static_cast<RSoVHal *>(rsc->mHal.drv); + RSoVContext *rsov = hal->mRSoV; + + std::unique_ptr<RsdCpuReference::CpuScript> cs(hal->mCpuRef->createScript( + script, resName, cacheDir, bitcode, bitcodeSize, flags)); + if (cs == nullptr) { + return false; + } + cs->populateScript(script); + + RSoVScript *rsovScript = new RSoVScript(rsov, std::move(spvWords)); + + if (!rsovScript) { + ALOGV("Failed creating a RSoV script"); + // Uncomment below to choose CPU driver instead + // script->mHal.drv = cs; + return false; + } + + rsovScript->setCpuScript(cs.release()); + script->mHal.drv = rsovScript; + + return true; +} + +bool rsovInitIntrinsic(const Context *rsc, Script *s, RsScriptIntrinsicID iid, + Element *e) { + RSoVHal *dc = (RSoVHal *)rsc->mHal.drv; + RsdCpuReference::CpuScript *cs = dc->mCpuRef->createIntrinsic(s, iid, e); + if (cs == nullptr) { + return false; + } + s->mHal.drv = cs; + cs->populateScript(s); + return true; +} + +void rsovScriptInvokeForEach(const Context *rsc, Script *s, uint32_t slot, + const Allocation *ain, Allocation *aout, + const void *usr, size_t usrLen, + const RsScriptCall *sc) { + if (ain == nullptr) { + rsovScriptInvokeForEachMulti(rsc, s, slot, nullptr, 0, aout, usr, usrLen, + sc); + } else { + const Allocation *ains[1] = {ain}; + + rsovScriptInvokeForEachMulti(rsc, s, slot, ains, 1, aout, usr, usrLen, sc); + } +} + +void rsovScriptInvokeForEachMulti(const Context *rsc, Script *s, uint32_t slot, + const Allocation **ains, size_t inLen, + Allocation *aout, const void *usr, + size_t usrLen, const RsScriptCall *sc) { + RsdCpuReference::CpuScript *cs = (RsdCpuReference::CpuScript *)s->mHal.drv; + cs->invokeForEach(slot, ains, inLen, aout, usr, usrLen, sc); +} + +int rsovScriptInvokeRoot(const Context *dc, Script *s) { + RsdCpuReference::CpuScript *cs = (RsdCpuReference::CpuScript *)s->mHal.drv; + return cs->invokeRoot(); +} + +void rsovScriptInvokeInit(const Context *dc, Script *s) { + RsdCpuReference::CpuScript *cs = (RsdCpuReference::CpuScript *)s->mHal.drv; + cs->invokeInit(); +} + +void rsovScriptInvokeFreeChildren(const Context *dc, Script *s) { + RsdCpuReference::CpuScript *cs = (RsdCpuReference::CpuScript *)s->mHal.drv; + cs->invokeFreeChildren(); +} + +void rsovScriptInvokeFunction(const Context *dc, Script *s, uint32_t slot, + const void *params, size_t paramLength) { + RsdCpuReference::CpuScript *cs = (RsdCpuReference::CpuScript *)s->mHal.drv; + cs->invokeFunction(slot, params, paramLength); +} + +void rsovScriptInvokeReduce(const Context *dc, Script *s, uint32_t slot, + const Allocation **ains, size_t inLen, + Allocation *aout, const RsScriptCall *sc) { + RsdCpuReference::CpuScript *cs = (RsdCpuReference::CpuScript *)s->mHal.drv; + cs->invokeReduce(slot, ains, inLen, aout, sc); +} + +void rsovScriptSetGlobalVar(const Context *dc, const Script *s, uint32_t slot, + void *data, size_t dataLength) { + RsdCpuReference::CpuScript *cs = (RsdCpuReference::CpuScript *)s->mHal.drv; + cs->setGlobalVar(slot, data, dataLength); +} + +void rsovScriptGetGlobalVar(const Context *dc, const Script *s, uint32_t slot, + void *data, size_t dataLength) { + RsdCpuReference::CpuScript *cs = (RsdCpuReference::CpuScript *)s->mHal.drv; + cs->getGlobalVar(slot, data, dataLength); +} + +void rsovScriptSetGlobalVarWithElemDims( + const Context *dc, const Script *s, uint32_t slot, void *data, + size_t dataLength, const android::renderscript::Element *elem, + const uint32_t *dims, size_t dimLength) { + RsdCpuReference::CpuScript *cs = (RsdCpuReference::CpuScript *)s->mHal.drv; + cs->setGlobalVarWithElemDims(slot, data, dataLength, elem, dims, dimLength); +} + +void rsovScriptSetGlobalBind(const Context *dc, const Script *s, uint32_t slot, + Allocation *data) { + RsdCpuReference::CpuScript *cs = (RsdCpuReference::CpuScript *)s->mHal.drv; + cs->setGlobalBind(slot, data); +} + +void rsovScriptSetGlobalObj(const Context *dc, const Script *s, uint32_t slot, + ObjectBase *data) { + RsdCpuReference::CpuScript *cs = (RsdCpuReference::CpuScript *)s->mHal.drv; + cs->setGlobalObj(slot, data); +} + +void rsovScriptDestroy(const Context *dc, Script *s) { + RsdCpuReference::CpuScript *cs = (RsdCpuReference::CpuScript *)s->mHal.drv; + delete cs; + s->mHal.drv = nullptr; +} + +Allocation *rsovScriptGetAllocationForPointer( + const android::renderscript::Context *dc, + const android::renderscript::Script *sc, const void *ptr) { + RsdCpuReference::CpuScript *cs = (RsdCpuReference::CpuScript *)sc->mHal.drv; + return cs->getAllocationForPointer(ptr); +} + +void rsovScriptUpdateCachedObject(const Context *rsc, const Script *script, + rs_script *obj) { + obj->p = script; +#ifdef __LP64__ + obj->r = nullptr; + if (script != nullptr) { + obj->v1 = script->mHal.drv; + } else { + obj->v1 = nullptr; + } + obj->v2 = nullptr; +#endif +} diff --git a/rsov/driver/rsovScript.h b/rsov/driver/rsovScript.h new file mode 100644 index 00000000..e9030d1c --- /dev/null +++ b/rsov/driver/rsovScript.h @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RSOV_SCRIPT_H +#define RSOV_SCRIPT_H + +#include <vulkan/vulkan.h> + +#include <vector> + +#include "rsDefines.h" +#include "rs_hal.h" +#include "rsd_cpu.h" + +namespace android { +namespace renderscript { + +class Allocation; +class Context; +class Element; +class Script; +class ScriptC; + +namespace rsov { + +class RSoVAllocation; +class RSoVContext; + +// TODO: CpuScript is a bad name for the base class. Fix with a refactoring. +class RSoVScript : RsdCpuReference::CpuScript { + public: + RSoVScript(RSoVContext *context, std::vector<uint32_t> &&spvWords); + RSoVScript(RSoVContext *context, + const std::vector<uint32_t> &spvWords) = delete; + + virtual ~RSoVScript(); + + void populateScript(Script *) override; + void invokeFunction(uint32_t slot, const void *params, + size_t paramLength) override; + int invokeRoot() override; + + void invokeForEach(uint32_t slot, const Allocation **ains, uint32_t inLen, + Allocation *aout, const void *usr, uint32_t usrLen, + const RsScriptCall *sc) override; + + void invokeReduce(uint32_t slot, const Allocation **ains, uint32_t inLen, + Allocation *aout, const RsScriptCall *sc) override; + + void invokeInit() override; + void invokeFreeChildren() override; + + void setGlobalVar(uint32_t slot, const void *data, + size_t dataLength) override; + void getGlobalVar(uint32_t slot, void *data, size_t dataLength) override; + void setGlobalVarWithElemDims(uint32_t slot, const void *data, + size_t dataLength, const Element *e, + const uint32_t *dims, + size_t dimLength) override; + + void setGlobalBind(uint32_t slot, Allocation *data) override; + void setGlobalObj(uint32_t slot, ObjectBase *obj) override; + + Allocation *getAllocationForPointer(const void *ptr) const override; + + // Returns number of global variables in this Script (may be 0 if + // compiler is not configured to emit this information). + int getGlobalEntries() const override; + // Returns the name of the global variable at index i. + const char *getGlobalName(int i) const override; + // Returns the CPU address of the global variable at index i. + const void *getGlobalAddress(int i) const override; + // Returns the size (in bytes) of the global variable at index i. + size_t getGlobalSize(int i) const override; + // Returns the properties of the global variable at index i. + uint32_t getGlobalProperties(int i) const override; + + void setCpuScript(RsdCpuReference::CpuScript *cs) { mCpuScript = cs; } + + RsdCpuReference::CpuScript *getCpuScript() const { return mCpuScript; } + + private: + void InitDescriptorAndPipelineLayouts(); + void InitShader(); + void InitDescriptorPool(); + void InitDescriptorSet(const RSoVAllocation *inputAllocation, + RSoVAllocation *outputAllocation); + void InitPipelineCache(); + void InitPipeline(); + void runForEach(const RSoVAllocation *input, RSoVAllocation *output); + + RSoVContext *mRSoV; + VkDevice mDevice; + std::vector<uint32_t> mSPIRVWords; + RsdCpuReference::CpuScript *mCpuScript; + + static constexpr int NUM_DESCRIPTOR_SETS = 1; + std::vector<VkDescriptorSetLayout> mDescLayout; + VkPipelineLayout mPipelineLayout; + VkPipeline mComputePipeline; + // TODO: Multiple stages for multiple kernels + VkPipelineShaderStageCreateInfo mShaderStage; + VkDescriptorPool mDescPool; + std::vector<VkDescriptorSet> mDescSet; +}; + +} // namespace rsov +} // namespace renderscript +} // namespace android + +extern bool rsovScriptInit(const android::renderscript::Context *rsc, + android::renderscript::ScriptC *script, + char const *resName, char const *cacheDir, + uint8_t const *bitcode, size_t bitcodeSize, + uint32_t flags); + +extern bool rsovInitIntrinsic(const android::renderscript::Context *rsc, + android::renderscript::Script *s, + RsScriptIntrinsicID iid, + android::renderscript::Element *e); + +extern void rsovScriptInvokeFunction(const android::renderscript::Context *dc, + android::renderscript::Script *script, + uint32_t slot, const void *params, + size_t paramLength); + +extern void rsovScriptInvokeForEach( + const android::renderscript::Context *rsc, android::renderscript::Script *s, + uint32_t slot, const android::renderscript::Allocation *ain, + android::renderscript::Allocation *aout, const void *usr, size_t usrLen, + const RsScriptCall *sc); + +extern void rsovScriptInvokeReduce( + const android::renderscript::Context *rsc, android::renderscript::Script *s, + uint32_t slot, const android::renderscript::Allocation **ains, size_t inLen, + android::renderscript::Allocation *aout, const RsScriptCall *sc); + +extern void rsovScriptInvokeForEachMulti( + const android::renderscript::Context *rsc, android::renderscript::Script *s, + uint32_t slot, const android::renderscript::Allocation **ains, size_t inLen, + android::renderscript::Allocation *aout, const void *usr, size_t usrLen, + const RsScriptCall *sc); + +extern int rsovScriptInvokeRoot(const android::renderscript::Context *dc, + android::renderscript::Script *script); + +extern void rsovScriptInvokeInit(const android::renderscript::Context *dc, + android::renderscript::Script *script); + +extern void rsovScriptInvokeFreeChildren( + const android::renderscript::Context *dc, + android::renderscript::Script *script); + +extern void rsovScriptSetGlobalVar(const android::renderscript::Context *, + const android::renderscript::Script *, + uint32_t slot, void *data, size_t dataLen); + +extern void rsovScriptGetGlobalVar(const android::renderscript::Context *, + const android::renderscript::Script *, + uint32_t slot, void *data, size_t dataLen); + +extern void rsovScriptSetGlobalVarWithElemDims( + const android::renderscript::Context *, + const android::renderscript::Script *, uint32_t slot, void *data, + size_t dataLength, const android::renderscript::Element *, + const uint32_t *dims, size_t dimLength); +extern void rsovScriptSetGlobalBind(const android::renderscript::Context *, + const android::renderscript::Script *, + uint32_t slot, + android::renderscript::Allocation *data); + +extern void rsovScriptSetGlobalObj(const android::renderscript::Context *, + const android::renderscript::Script *, + uint32_t slot, + android::renderscript::ObjectBase *data); + +extern void rsovScriptSetGlobal(const android::renderscript::Context *dc, + const android::renderscript::Script *script, + uint32_t slot, void *data, size_t dataLength); +extern void rsovScriptGetGlobal(const android::renderscript::Context *dc, + const android::renderscript::Script *script, + uint32_t slot, void *data, size_t dataLength); +extern void rsovScriptDestroy(const android::renderscript::Context *dc, + android::renderscript::Script *script); + +extern android::renderscript::Allocation *rsovScriptGetAllocationForPointer( + const android::renderscript::Context *dc, + const android::renderscript::Script *script, const void *); + +extern void rsovScriptUpdateCachedObject( + const android::renderscript::Context *rsc, + const android::renderscript::Script *script, + android::renderscript::rs_script *obj); + +#endif // RSOV_SCRIPT_H diff --git a/rsov/driver/rsovScriptGroup.cpp b/rsov/driver/rsovScriptGroup.cpp new file mode 100644 index 00000000..3603c04b --- /dev/null +++ b/rsov/driver/rsovScriptGroup.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rsovCore.h" + +#include "rsAllocation.h" +#include "rsContext.h" +#include "rsScript.h" +#include "rsScriptGroup.h" +#include "rsd_cpu.h" + +using android::renderscript::Allocation; +using android::renderscript::Context; +using android::renderscript::RsdCpuReference; +using android::renderscript::ScriptGroup; +using android::renderscript::ScriptGroupBase; +using android::renderscript::ScriptKernelID; +using android::renderscript::rs_script_group; + +bool rsovScriptGroupInit(const Context *rsc, ScriptGroupBase *sg) { + // Always falls back to CPU implmentation of ScriptGroup + RSoVHal *dc = (RSoVHal *)rsc->mHal.drv; + + sg->mHal.drv = dc->mCpuRef->createScriptGroup(sg); + return sg->mHal.drv != nullptr; +} + +void rsovScriptGroupSetInput(const Context *rsc, const ScriptGroup *sg, + const ScriptKernelID *kid, Allocation *) {} + +void rsovScriptGroupSetOutput(const Context *rsc, const ScriptGroup *sg, + const ScriptKernelID *kid, Allocation *) {} + +void rsovScriptGroupExecute(const Context *rsc, const ScriptGroupBase *sg) { + RsdCpuReference::CpuScriptGroupBase *sgi = + (RsdCpuReference::CpuScriptGroupBase *)sg->mHal.drv; + sgi->execute(); +} + +void rsovScriptGroupDestroy(const Context *rsc, const ScriptGroupBase *sg) { + RsdCpuReference::CpuScriptGroupBase *sgi = + (RsdCpuReference::CpuScriptGroupBase *)sg->mHal.drv; + delete sgi; +} diff --git a/rsov/driver/rsovScriptGroup.h b/rsov/driver/rsovScriptGroup.h new file mode 100644 index 00000000..1a16136e --- /dev/null +++ b/rsov/driver/rsovScriptGroup.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RSOV_SCRIPT_GROUP_H +#define RSOV_SCRIPT_GROUP_H + +#include "rs_hal.h" + +bool rsovScriptGroupInit(const android::renderscript::Context *rsc, + android::renderscript::ScriptGroupBase *sg); +void rsovScriptGroupSetInput(const android::renderscript::Context *rsc, + const android::renderscript::ScriptGroup *sg, + const android::renderscript::ScriptKernelID *kid, + android::renderscript::Allocation *); +void rsovScriptGroupSetOutput(const android::renderscript::Context *rsc, + const android::renderscript::ScriptGroup *sg, + const android::renderscript::ScriptKernelID *kid, + android::renderscript::Allocation *); +void rsovScriptGroupExecute(const android::renderscript::Context *rsc, + const android::renderscript::ScriptGroupBase *sg); +void rsovScriptGroupDestroy(const android::renderscript::Context *rsc, + const android::renderscript::ScriptGroupBase *sg); + +#endif // RSOV_SCRIPT_GROUP_H diff --git a/rsov/driver/rsovType.cpp b/rsov/driver/rsovType.cpp new file mode 100644 index 00000000..e18400a8 --- /dev/null +++ b/rsov/driver/rsovType.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rsContext.h" +#include "rsType.h" + +using android::renderscript::Context; +using android::renderscript::Type; +using android::renderscript::rs_type; + +bool rsovTypeInit(const Context *, const Type *t) { return true; } + +void rsovTypeDestroy(const Context *rsc, const Type *t) {} + +void rsovTypeUpdateCachedObject(const Context *rsc, const Type *t, + rs_type *obj) { + obj->p = t; +#ifdef __LP64__ + obj->r = nullptr; + obj->v1 = nullptr; + obj->v2 = nullptr; +#endif +} diff --git a/rsov/driver/rsovType.h b/rsov/driver/rsovType.h new file mode 100644 index 00000000..39f31dc7 --- /dev/null +++ b/rsov/driver/rsovType.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RSOV_TYPE_H +#define RSOV_TYPE_H + +#include "rs_hal.h" + +extern bool rsovTypeInit(const android::renderscript::Context *rsc, + const android::renderscript::Type *); + +extern void rsovTypeDestroy(const android::renderscript::Context *rsc, + const android::renderscript::Type *); + +extern void rsovTypeUpdateCachedObject( + const android::renderscript::Context *rsc, + const android::renderscript::Type *, android::renderscript::rs_type *obj); + +#endif // RSD_TYPE_H diff --git a/rsov/tests/RSoVTest/Android.mk b/rsov/tests/RSoVTest/Android.mk new file mode 100644 index 00000000..882de995 --- /dev/null +++ b/rsov/tests/RSoVTest/Android.mk @@ -0,0 +1,29 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests +LOCAL_STATIC_JAVA_LIBRARIES := android-support-test + +LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) + +LOCAL_RENDERSCRIPT_FLAGS := -target-api 0 + +LOCAL_PACKAGE_NAME := RSoVTest + +include $(BUILD_PACKAGE) diff --git a/rsov/tests/RSoVTest/AndroidManifest.xml b/rsov/tests/RSoVTest/AndroidManifest.xml new file mode 100644 index 00000000..23a4e5c2 --- /dev/null +++ b/rsov/tests/RSoVTest/AndroidManifest.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.rs.rsov.test"> + <application + android:largeHeap="true" + android:label="_RSoV_Test" + android:icon="@drawable/test_pattern"> + <uses-library android:name="android.test.runner" /> + <activity android:name="RSoVTest" + android:screenOrientation="portrait"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + + <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.rs.rsov.test"/> +</manifest> diff --git a/rsov/tests/RSoVTest/res/drawable-nodpi/test_pattern.png b/rsov/tests/RSoVTest/res/drawable-nodpi/test_pattern.png Binary files differnew file mode 100644 index 00000000..7b344380 --- /dev/null +++ b/rsov/tests/RSoVTest/res/drawable-nodpi/test_pattern.png diff --git a/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/RSoVTest.java b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/RSoVTest.java new file mode 100644 index 00000000..f9035d29 --- /dev/null +++ b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/RSoVTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.rsov.test; + +import android.app.ListActivity; +import android.os.Bundle; +import android.renderscript.RenderScript; +import android.util.Log; + +public class RSoVTest extends ListActivity { + + private static final String LOG_TAG = "RSTest"; + private static final boolean DEBUG = false; + private static final boolean LOG_ENABLED = false; + + private RenderScript mRS; + private RSoVTestCore RSTC; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + mRS = RenderScript.create(this); + + RSTC = new RSoVTestCore(this); + RSTC.init(mRS); + } + + static void log(String message) { + if (LOG_ENABLED) { + Log.v(LOG_TAG, message); + } + } + + +} diff --git a/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/RSoVTestCore.java b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/RSoVTestCore.java new file mode 100644 index 00000000..e3d80233 --- /dev/null +++ b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/RSoVTestCore.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.rsov.test; + +import android.app.ListActivity; +import android.renderscript.Allocation; +import android.renderscript.RenderScript; +import android.widget.ArrayAdapter; + +import java.util.ArrayList; +import java.util.ListIterator; +import java.util.Timer; +import java.util.TimerTask; + +public class RSoVTestCore { + ListActivity mCtx; + + public RSoVTestCore(ListActivity ctx) { + mCtx = ctx; + } + + private RenderScript mRS; + + private ArrayList<UnitTest> unitTests; + private ListIterator<UnitTest> test_iter; + private UnitTest activeTest; + private boolean stopTesting; + + private ScriptField_ListAllocs_s mListAllocs; + + private ArrayAdapter<UnitTest> testAdapter; + + /* Periodic timer for ensuring future tests get scheduled */ + private Timer mTimer; + public static final int RS_TIMER_PERIOD = 100; + + public void init(RenderScript rs) { + mRS = rs; + stopTesting = false; + + unitTests = new ArrayList<UnitTest>(); + + unitTests.add(new UT_invert(this, mCtx)); + unitTests.add(new UT_modulo(this, mCtx)); + + UnitTest[] uta = new UnitTest[unitTests.size()]; + uta = unitTests.toArray(uta); + + /* + mListAllocs = new ScriptField_ListAllocs_s(mRS, uta.length); + for (int i = 0; i < uta.length; i++) { + ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item(); + listElem.text = Allocation.createFromString(mRS, uta[i].name, Allocation.USAGE_SCRIPT); + listElem.result = uta[i].getResult(); + mListAllocs.set(listElem, i, false); + uta[i].setItem(listElem); + } + + mListAllocs.copyAll(); + */ + testAdapter = new ArrayAdapter<UnitTest>(mCtx, android.R.layout.simple_list_item_1, unitTests); + mCtx.setListAdapter(testAdapter); + + test_iter = unitTests.listIterator(); + refreshTestResults(); /* Kick off the first test */ + + TimerTask pTask = new TimerTask() { + public void run() { + refreshTestResults(); + } + }; + + mTimer = new Timer(); + mTimer.schedule(pTask, RS_TIMER_PERIOD, RS_TIMER_PERIOD); + } + + public void checkAndRunNextTest() { + mCtx.runOnUiThread(new Runnable() { + public void run() { + if (testAdapter != null) + testAdapter.notifyDataSetChanged(); + } + }); + + if (activeTest != null) { + if (!activeTest.isAlive()) { + /* Properly clean up on our last test */ + try { + activeTest.join(); + } catch (InterruptedException e) { + } + activeTest = null; + } + } + + if (!stopTesting && activeTest == null) { + if (test_iter.hasNext()) { + activeTest = test_iter.next(); + activeTest.start(); + /* This routine will only get called once when a new test + * should start running. The message handler in UnitTest.java + * ensures this. */ + } else { + if (mTimer != null) { + mTimer.cancel(); + mTimer.purge(); + mTimer = null; + } + } + } + } + + public void refreshTestResults() { + checkAndRunNextTest(); + } + + public void cleanup() { + stopTesting = true; + UnitTest t = activeTest; + + /* Stop periodic refresh of testing */ + if (mTimer != null) { + mTimer.cancel(); + mTimer.purge(); + mTimer = null; + } + + /* Wait to exit until we finish the current test */ + if (t != null) { + try { + t.join(); + } catch (InterruptedException e) { + } + t = null; + } + + } + +} diff --git a/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/UT_invert.java b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/UT_invert.java new file mode 100644 index 00000000..017aa061 --- /dev/null +++ b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/UT_invert.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.rsov.test; + +import android.content.Context; +import android.renderscript.Allocation; +import android.renderscript.Element; +import android.renderscript.RenderScript; +import android.renderscript.Type; +import android.util.Log; + +public class UT_invert extends UnitTest { + protected UT_invert(RSoVTestCore rstc, Context ctx) { + super(rstc, "invert", ctx); + } + + private boolean Test(int width, int height, int depth) { + RenderScript pRS = RenderScript.create(mCtx); + ScriptC_invert s = new ScriptC_invert(pRS); + + Type.Builder typeBuilder = new Type.Builder(pRS, Element.F32_4(pRS)); + typeBuilder.setX(width); + if (height > 0) { + typeBuilder.setY(height); + if (depth > 0) { + typeBuilder.setZ(depth); + } + } + + if (depth < 1) { + depth = 1; + } + + if (height < 1) { + height = 1; + } + + Allocation A = Allocation.createTyped(pRS, typeBuilder.create()); + Allocation B = Allocation.createTyped(pRS, typeBuilder.create()); + + float a[] = new float[width * height * depth * 4]; + float b[] = new float[width * height * depth * 4]; + + java.util.Random rand = new java.util.Random(); + + for (int i = 0; i < width * height * depth * 4; i++) { + a[i] = rand.nextFloat(); + } + + A.copyFrom(a); + + s.forEach_invert(A, B); + + B.copyTo(b); + + B.destroy(); + A.destroy(); + + pRS.finish(); + pRS.destroy(); + + boolean failed = false; + for (int i = 0; i < width * height * depth * 4; i++) { + if (b[i] != 1.0f - a[i]) { + Log.e(name, "expects " + (1.0f - a[i]) + " for element " + i + + ". got " + b[i]); + failed = true; + break; + } + } + + return !failed; + } + + public void run() { + final int X = 96; + final int Y = 64; + final int Z = 32; + + if (Test(X, 0, 0) && Test(X, Y, 0)) { + passTest(); + return; + } + + failTest(); + } +} diff --git a/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/UT_modulo.java b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/UT_modulo.java new file mode 100644 index 00000000..bb55612b --- /dev/null +++ b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/UT_modulo.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.rsov.test; + +import android.content.Context; +import android.renderscript.Allocation; +import android.renderscript.Element; +import android.renderscript.RenderScript; +import android.renderscript.Type; +import android.util.Log; + +public class UT_modulo extends UnitTest { + private Allocation A; + private Allocation B; + private final int X = 96; + private final int Y = 64; + + protected UT_modulo(RSoVTestCore rstc, Context ctx) { + super(rstc, "modulo", ctx); + } + + private void initializeGlobals(RenderScript RS, ScriptC_modulo s) { + Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS)); + typeBuilder.setX(X); + typeBuilder.setY(Y); + + A = Allocation.createTyped(RS, typeBuilder.create()); + B = Allocation.createTyped(RS, typeBuilder.create()); + return; + } + + public void run() { + RenderScript pRS = RenderScript.create(mCtx); + ScriptC_modulo s = new ScriptC_modulo(pRS); + + initializeGlobals(pRS, s); + + int a[] = new int[X*Y]; + int b[] = new int[X*Y]; + + java.util.Random rand = new java.util.Random(); + + for (int i = 0; i < X * Y; i++) { + a[i] = rand.nextInt(65536); + } + + A.copyFrom(a); + + s.forEach_modulo(A, B); + + B.copyTo(b); + + pRS.finish(); + pRS.destroy(); + + boolean failed = false; + for (int i = 0; i < X * Y; i++) { + int expected = a[i] % 256; + if (b[i] != expected) { + Log.e(name, "expects " + expected + " got " + b[i]); + failed = true; + break; + } + } + + if (failed) { + failTest(); + } else { + passTest(); + } + } +} diff --git a/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/UnitTest.java b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/UnitTest.java new file mode 100644 index 00000000..f69a96af --- /dev/null +++ b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/UnitTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.rsov.test; + +import android.content.Context; +import android.renderscript.RenderScript.RSMessageHandler; +import android.util.Log; + +public class UnitTest extends Thread { + public String name; + private int result; + private ScriptField_ListAllocs_s.Item mItem; + private RSoVTestCore mRSTC; + private boolean msgHandled; + protected Context mCtx; + + /* These constants must match those in shared.rsh */ + public static final int RS_MSG_TEST_PASSED = 100; + public static final int RS_MSG_TEST_FAILED = 101; + public static final int TEST_PASSED = 1; + public static final int TEST_FAILED = -1; + + private static int numTests = 0; + public int testID; + + protected UnitTest(RSoVTestCore rstc, String n, int initResult, Context ctx) { + super(); + mRSTC = rstc; + name = n; + msgHandled = false; + mCtx = ctx; + result = initResult; + testID = numTests++; + } + + protected UnitTest(RSoVTestCore rstc, String n, Context ctx) { + this(rstc, n, 0, ctx); + } + + protected UnitTest(RSoVTestCore rstc, Context ctx) { + this(rstc, "<Unknown>", ctx); + } + + protected UnitTest(Context ctx) { + this(null, ctx); + } + + protected void _RS_ASSERT(String message, boolean b) { + if (b == false) { + Log.e(name, message + " FAILED"); + failTest(); + } + } + + private void updateUI() { + msgHandled = true; + if (mItem != null) { + mItem.result = result; + if (mRSTC != null) { + // Add null check for mRSTC, for instrumentation tests. + try { + mRSTC.refreshTestResults(); + } catch (IllegalStateException e) { + /* Ignore the case where our message receiver has been + disconnected. This happens when we leave the application + before it finishes running all of the unit tests. */ + } + } + } + } + + protected RSMessageHandler mRsMessage = new RSMessageHandler() { + public void run() { + if (result == 0) { + switch (mID) { + case RS_MSG_TEST_PASSED: + result = TEST_PASSED; + break; + case RS_MSG_TEST_FAILED: + result = TEST_FAILED; + break; + default: + RSoVTest.log("Unit test got unexpected message"); + return; + } + } + + updateUI(); + } + }; + + public void waitForMessage() { + while (!msgHandled) { + yield(); + } + } + + public int getResult() { + return result; + } + + public void failTest() { + result = TEST_FAILED; + updateUI(); + } + + public void passTest() { + if (result != TEST_FAILED) { + result = TEST_PASSED; + } + updateUI(); + } + + public String toString() { + String out = name; + if (result == TEST_PASSED) { + out += " - PASSED"; + } else if (result == TEST_FAILED) { + out += " - FAILED"; + } + return out; + } + + public void setItem(ScriptField_ListAllocs_s.Item item) { + mItem = item; + } + + public void run() { + /* This method needs to be implemented for each subclass */ + if (mRSTC != null) { + mRSTC.refreshTestResults(); + } + } +} diff --git a/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/invert.rs b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/invert.rs new file mode 100644 index 00000000..eb89da24 --- /dev/null +++ b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/invert.rs @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma version(1) + +#pragma rs java_package_name(com.android.rs.rsov.test) + +float4 RS_KERNEL invert(float4 a) { + return 1.0f - a; +} diff --git a/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/modulo.rs b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/modulo.rs new file mode 100644 index 00000000..410dccf3 --- /dev/null +++ b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/modulo.rs @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma version(1) + +#pragma rs java_package_name(com.android.rs.rsov.test) + +int RS_KERNEL modulo(int a) { + return a % 256; +} diff --git a/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/rslist.rs b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/rslist.rs new file mode 100644 index 00000000..2d5fa59a --- /dev/null +++ b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/rslist.rs @@ -0,0 +1,25 @@ +// Copyright (C) 2009 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma version(1) + +#pragma rs java_package_name(com.android.rs.rsov.test) + +typedef struct ListAllocs_s { + rs_allocation text; + int result; +} ListAllocs; + +ListAllocs *gList; + diff --git a/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/shared.rsh b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/shared.rsh new file mode 100644 index 00000000..481e874b --- /dev/null +++ b/rsov/tests/RSoVTest/src/com/android/rs/rsov/test/shared.rsh @@ -0,0 +1,116 @@ +#pragma version(1) + +#pragma rs java_package_name(com.android.rs.rsov.test) + +typedef struct TestResult_s { + rs_allocation name; + bool pass; + float score; + int64_t time; +} TestResult; +//TestResult *g_results; + +static int64_t g_time; + +static inline void start(void) { + g_time = rsUptimeMillis(); +} + +static inline float end(uint32_t idx) { + int64_t t = rsUptimeMillis() - g_time; + //g_results[idx].time = t; + //rsDebug("test time", (int)t); + return ((float)t) / 1000.f; +} + +#define _RS_ASSERT(b) \ +do { \ + if (!(b)) { \ + failed = true; \ + rsDebug(#b " FAILED", 0); \ + } \ +\ +} while (0) + +#define _RS_ASSERT_EQU(e1, e2) \ + (((e1) != (e2)) ? (failed = true, rsDebug(#e1 " != " #e2, (e1), (e2)), false) : true) + +static const int iposinf = 0x7f800000; +static const int ineginf = 0xff800000; + +static inline const float posinf() { + float f = *((float*)&iposinf); + return f; +} + +static inline const float neginf() { + float f = *((float*)&ineginf); + return f; +} + +static inline bool isposinf(float f) { + int i = *((int*)(void*)&f); + return (i == iposinf); +} + +static inline bool isneginf(float f) { + int i = *((int*)(void*)&f); + return (i == ineginf); +} + +static inline bool isnan(float f) { + int i = *((int*)(void*)&f); + return (((i & 0x7f800000) == 0x7f800000) && (i & 0x007fffff)); +} + +static inline bool isposzero(float f) { + int i = *((int*)(void*)&f); + return (i == 0x00000000); +} + +static inline bool isnegzero(float f) { + int i = *((int*)(void*)&f); + return (i == 0x80000000); +} + +static inline bool iszero(float f) { + return isposzero(f) || isnegzero(f); +} + +/* Absolute epsilon used for floats. Value is similar to float.h. */ +#ifndef FLT_EPSILON +#define FLT_EPSILON 1.19e7f +#endif +/* Max ULPs while still being considered "equal". Only used when this number + of ULPs is of a greater size than FLT_EPSILON. */ +#define FLT_MAX_ULP 1 + +/* Calculate the difference in ULPs between the two values. (Return zero on + perfect equality.) */ +static inline int float_dist(float f1, float f2) { + return *((int *)(&f1)) - *((int *)(&f2)); +} + +/* Check if two floats are essentially equal. Will fail with some values + due to design. (Validate using FLT_EPSILON or similar if necessary.) */ +static inline bool float_almost_equal(float f1, float f2) { + int *i1 = (int*)(&f1); + int *i2 = (int*)(&f2); + + // Check for sign equality + if ( ((*i1 >> 31) == 0) != ((*i2 >> 31) == 0) ) { + // Handle signed zeroes + if (f1 == f2) + return true; + return false; + } + + // Check with ULP distance + if (float_dist(f1, f2) > FLT_MAX_ULP) + return false; + return true; +} + +/* These constants must match those in UnitTest.java */ +static const int RS_MSG_TEST_PASSED = 100; +static const int RS_MSG_TEST_FAILED = 101; |