1069 lines
34 KiB
C++
1069 lines
34 KiB
C++
/*
|
|
* Copyright 2013, The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <sys/stat.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <iostream>
|
|
|
|
#include <cstdarg>
|
|
#include <cctype>
|
|
|
|
#include <algorithm>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
#include "os_sep.h"
|
|
#include "slang_rs_context.h"
|
|
#include "slang_rs_export_var.h"
|
|
#include "slang_rs_export_foreach.h"
|
|
#include "slang_rs_export_func.h"
|
|
#include "slang_rs_reflect_utils.h"
|
|
#include "slang_version.h"
|
|
|
|
#include "slang_rs_reflection_cpp.h"
|
|
|
|
using namespace std;
|
|
|
|
namespace slang {
|
|
|
|
const char kRsTypeItemClassName[] = "Item";
|
|
const char kRsElemPrefix[] = "__rs_elem_";
|
|
// The name of the Allocation type that is reflected in C++
|
|
const char kAllocationSp[] = "android::RSC::sp<android::RSC::Allocation>";
|
|
|
|
static const char *GetMatrixTypeName(const RSExportMatrixType *EMT) {
|
|
static const char *MatrixTypeCNameMap[] = {
|
|
"rs_matrix2x2", "rs_matrix3x3", "rs_matrix4x4",
|
|
};
|
|
unsigned Dim = EMT->getDim();
|
|
|
|
if ((Dim - 2) < (sizeof(MatrixTypeCNameMap) / sizeof(const char *)))
|
|
return MatrixTypeCNameMap[EMT->getDim() - 2];
|
|
|
|
slangAssert(false && "GetMatrixTypeName : Unsupported matrix dimension");
|
|
return nullptr;
|
|
}
|
|
|
|
static std::string GetTypeName(const RSExportType *ET, bool PreIdentifier = true) {
|
|
if((!PreIdentifier) && (ET->getClass() != RSExportType::ExportClassConstantArray)) {
|
|
slangAssert(false && "Non-array type post identifier?");
|
|
return "";
|
|
}
|
|
switch (ET->getClass()) {
|
|
case RSExportType::ExportClassPrimitive: {
|
|
const RSExportPrimitiveType *EPT =
|
|
static_cast<const RSExportPrimitiveType *>(ET);
|
|
if (EPT->isRSObjectType()) {
|
|
return std::string("android::RSC::sp<const android::RSC::") +
|
|
RSExportPrimitiveType::getRSReflectionType(EPT)->c_name + ">";
|
|
} else {
|
|
return RSExportPrimitiveType::getRSReflectionType(EPT)->c_name;
|
|
}
|
|
}
|
|
case RSExportType::ExportClassPointer: {
|
|
const RSExportType *PointeeType =
|
|
static_cast<const RSExportPointerType *>(ET)->getPointeeType();
|
|
|
|
if (PointeeType->getClass() != RSExportType::ExportClassRecord)
|
|
return kAllocationSp;
|
|
else
|
|
return PointeeType->getElementName();
|
|
}
|
|
case RSExportType::ExportClassVector: {
|
|
const RSExportVectorType *EVT = static_cast<const RSExportVectorType *>(ET);
|
|
std::stringstream VecName;
|
|
VecName << EVT->getRSReflectionType(EVT)->rs_c_vector_prefix
|
|
<< EVT->getNumElement();
|
|
return VecName.str();
|
|
}
|
|
case RSExportType::ExportClassMatrix: {
|
|
return GetMatrixTypeName(static_cast<const RSExportMatrixType *>(ET));
|
|
}
|
|
case RSExportType::ExportClassConstantArray: {
|
|
const RSExportConstantArrayType *CAT =
|
|
static_cast<const RSExportConstantArrayType *>(ET);
|
|
if (PreIdentifier) {
|
|
std::string ElementTypeName = GetTypeName(CAT->getElementType());
|
|
return ElementTypeName;
|
|
}
|
|
else {
|
|
std::stringstream ArraySpec;
|
|
ArraySpec << "[" << CAT->getNumElement() << "]";
|
|
return ArraySpec.str();
|
|
}
|
|
}
|
|
case RSExportType::ExportClassRecord: {
|
|
// TODO: Fix for C structs!
|
|
return ET->getElementName() + "." + kRsTypeItemClassName;
|
|
}
|
|
default: { slangAssert(false && "Unknown class of type"); }
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
RSReflectionCpp::RSReflectionCpp(const RSContext *Context,
|
|
const string &OutputDirectory,
|
|
const string &RSSourceFileName,
|
|
const string &BitCodeFileName)
|
|
: mRSContext(Context), mRSSourceFilePath(RSSourceFileName),
|
|
mBitCodeFilePath(BitCodeFileName), mOutputDirectory(OutputDirectory),
|
|
mNextExportVarSlot(0), mNextExportFuncSlot(0), mNextExportForEachSlot(0) {
|
|
mCleanedRSFileName = RootNameFromRSFileName(mRSSourceFilePath);
|
|
mClassName = "ScriptC_" + mCleanedRSFileName;
|
|
}
|
|
|
|
RSReflectionCpp::~RSReflectionCpp() {}
|
|
|
|
bool RSReflectionCpp::reflect() {
|
|
writeHeaderFile();
|
|
writeImplementationFile();
|
|
|
|
return true;
|
|
}
|
|
|
|
#define RS_TYPE_CLASS_NAME_PREFIX "ScriptField_"
|
|
|
|
bool RSReflectionCpp::writeHeaderFile() {
|
|
// Create the file and write the license note.
|
|
if (!mOut.startFile(mOutputDirectory, mClassName + ".h", mRSSourceFilePath,
|
|
mRSContext->getLicenseNote(), false,
|
|
mRSContext->getVerbose())) {
|
|
return false;
|
|
}
|
|
|
|
mOut.indent() << "#include \"RenderScript.h\"\n\n";
|
|
// Add NOLINT to suppress clang-tidy warnings of "using namespace".
|
|
// Keep "using namespace" to compile existing code.
|
|
mOut.indent() << "using namespace android::RSC; // NOLINT\n\n";
|
|
|
|
mOut.comment("This class encapsulates access to the exported elements of the script. "
|
|
"Typically, you would instantiate this class once, call the set_* methods "
|
|
"for each of the exported global variables you want to change, then call "
|
|
"one of the forEach_ methods to invoke a kernel.");
|
|
mOut.indent() << "class " << mClassName << " : public android::RSC::ScriptC";
|
|
mOut.startBlock();
|
|
|
|
mOut.decreaseIndent();
|
|
mOut.indent() << "private:\n";
|
|
mOut.increaseIndent();
|
|
|
|
genFieldsToStoreExportVariableValues();
|
|
genTypeInstancesUsedInForEach();
|
|
genFieldsForAllocationTypeVerification();
|
|
|
|
mOut.decreaseIndent();
|
|
mOut.indent() << "public:\n";
|
|
mOut.increaseIndent();
|
|
|
|
// Generate the constructor and destructor declarations.
|
|
mOut.indent() << mClassName << "(android::RSC::sp<android::RSC::RS> rs);\n";
|
|
mOut.indent() << "virtual ~" << mClassName << "();\n\n";
|
|
|
|
genExportVariablesGetterAndSetter();
|
|
genForEachDeclarations();
|
|
genExportFunctionDeclarations();
|
|
|
|
mOut.endBlock(true);
|
|
mOut.closeFile();
|
|
return true;
|
|
}
|
|
|
|
void RSReflectionCpp::genTypeInstancesUsedInForEach() {
|
|
for (auto I = mRSContext->export_foreach_begin(),
|
|
E = mRSContext->export_foreach_end();
|
|
I != E; I++) {
|
|
const RSExportForEach *EF = *I;
|
|
const RSExportType *OET = EF->getOutType();
|
|
|
|
if (OET) {
|
|
genTypeInstanceFromPointer(OET);
|
|
}
|
|
|
|
const RSExportForEach::InTypeVec &InTypes = EF->getInTypes();
|
|
|
|
for (RSExportForEach::InTypeIter BI = InTypes.begin(),
|
|
EI = InTypes.end(); BI != EI; BI++) {
|
|
|
|
genTypeInstanceFromPointer(*BI);
|
|
}
|
|
}
|
|
}
|
|
|
|
void RSReflectionCpp::genFieldsForAllocationTypeVerification() {
|
|
bool CommentAdded = false;
|
|
for (std::set<std::string>::iterator I = mTypesToCheck.begin(),
|
|
E = mTypesToCheck.end();
|
|
I != E; I++) {
|
|
if (!CommentAdded) {
|
|
mOut.comment("The following elements are used to verify the types of "
|
|
"allocations passed to kernels.");
|
|
CommentAdded = true;
|
|
}
|
|
mOut.indent() << "android::RSC::sp<const android::RSC::Element> "
|
|
<< kRsElemPrefix << *I << ";\n";
|
|
}
|
|
}
|
|
|
|
void RSReflectionCpp::genFieldsToStoreExportVariableValues() {
|
|
bool CommentAdded = false;
|
|
for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(),
|
|
E = mRSContext->export_vars_end();
|
|
I != E; I++) {
|
|
const RSExportVar *ev = *I;
|
|
if (ev->isConst()) {
|
|
continue;
|
|
}
|
|
if (!CommentAdded) {
|
|
mOut.comment("For each non-const variable exported by the script, we "
|
|
"have an equivalent field. This field contains the last "
|
|
"value this variable was set to using the set_ method. "
|
|
"This may not be current value of the variable in the "
|
|
"script, as the script is free to modify its internal "
|
|
"variable without changing this field. If the script "
|
|
"initializes the exported variable, the constructor will "
|
|
"initialize this field to the same value.");
|
|
CommentAdded = true;
|
|
}
|
|
mOut.indent() << GetTypeName(ev->getType()) << " " RS_EXPORT_VAR_PREFIX
|
|
<< ev->getName() << ";\n";
|
|
}
|
|
}
|
|
|
|
void RSReflectionCpp::genForEachDeclarations() {
|
|
bool CommentAdded = false;
|
|
for (RSContext::const_export_foreach_iterator
|
|
I = mRSContext->export_foreach_begin(),
|
|
E = mRSContext->export_foreach_end();
|
|
I != E; I++) {
|
|
const RSExportForEach *ForEach = *I;
|
|
|
|
if (ForEach->isDummyRoot()) {
|
|
mOut.indent() << "// No forEach_root(...)\n";
|
|
continue;
|
|
}
|
|
|
|
if (!CommentAdded) {
|
|
mOut.comment("For each kernel of the script corresponds one method. "
|
|
"That method queues the kernel for execution. The kernel "
|
|
"may not have completed nor even started by the time this "
|
|
"function returns. Calls that extract the data out of the "
|
|
"output allocation will wait for the kernels to complete.");
|
|
CommentAdded = true;
|
|
}
|
|
|
|
std::string FunctionStart = "void forEach_" + ForEach->getName() + "(";
|
|
mOut.indent() << FunctionStart;
|
|
|
|
ArgumentList Arguments;
|
|
const RSExportForEach::InVec &Ins = ForEach->getIns();
|
|
for (RSExportForEach::InIter BI = Ins.begin(), EI = Ins.end();
|
|
BI != EI; BI++) {
|
|
|
|
Arguments.push_back(Argument(kAllocationSp, (*BI)->getName()));
|
|
}
|
|
|
|
if (ForEach->hasOut() || ForEach->hasReturn()) {
|
|
Arguments.push_back(Argument(kAllocationSp, "aout"));
|
|
}
|
|
|
|
const RSExportRecordType *ERT = ForEach->getParamPacketType();
|
|
if (ERT) {
|
|
for (RSExportForEach::const_param_iterator i = ForEach->params_begin(),
|
|
e = ForEach->params_end();
|
|
i != e; i++) {
|
|
RSReflectionTypeData rtd;
|
|
(*i)->getType()->convertToRTD(&rtd);
|
|
Arguments.push_back(Argument(rtd.type->c_name, (*i)->getName()));
|
|
}
|
|
}
|
|
genArguments(Arguments, FunctionStart.length());
|
|
mOut << ");\n";
|
|
}
|
|
}
|
|
|
|
void RSReflectionCpp::genExportFunctionDeclarations() {
|
|
for (RSContext::const_export_func_iterator
|
|
I = mRSContext->export_funcs_begin(),
|
|
E = mRSContext->export_funcs_end();
|
|
I != E; I++) {
|
|
const RSExportFunc *ef = *I;
|
|
|
|
makeFunctionSignature(false, ef);
|
|
}
|
|
}
|
|
|
|
// forEach_* implementation
|
|
void RSReflectionCpp::genExportForEachBodies() {
|
|
uint32_t slot = 0;
|
|
for (auto I = mRSContext->export_foreach_begin(),
|
|
E = mRSContext->export_foreach_end();
|
|
I != E; I++, slot++) {
|
|
const RSExportForEach *ef = *I;
|
|
if (ef->isDummyRoot()) {
|
|
mOut.indent() << "// No forEach_root(...)\n";
|
|
continue;
|
|
}
|
|
|
|
ArgumentList Arguments;
|
|
std::string FunctionStart =
|
|
"void " + mClassName + "::forEach_" + ef->getName() + "(";
|
|
mOut.indent() << FunctionStart;
|
|
|
|
if (ef->hasIns()) {
|
|
// FIXME: Add support for kernels with multiple inputs.
|
|
slangAssert(ef->getIns().size() == 1);
|
|
Arguments.push_back(Argument(kAllocationSp, "ain"));
|
|
}
|
|
|
|
if (ef->hasOut() || ef->hasReturn()) {
|
|
Arguments.push_back(Argument(kAllocationSp, "aout"));
|
|
}
|
|
|
|
const RSExportRecordType *ERT = ef->getParamPacketType();
|
|
if (ERT) {
|
|
for (RSExportForEach::const_param_iterator i = ef->params_begin(),
|
|
e = ef->params_end();
|
|
i != e; i++) {
|
|
RSReflectionTypeData rtd;
|
|
(*i)->getType()->convertToRTD(&rtd);
|
|
Arguments.push_back(Argument(rtd.type->c_name, (*i)->getName()));
|
|
}
|
|
}
|
|
genArguments(Arguments, FunctionStart.length());
|
|
mOut << ")";
|
|
mOut.startBlock();
|
|
|
|
const RSExportType *OET = ef->getOutType();
|
|
const RSExportForEach::InTypeVec &InTypes = ef->getInTypes();
|
|
if (ef->hasIns()) {
|
|
// FIXME: Add support for kernels with multiple inputs.
|
|
slangAssert(ef->getIns().size() == 1);
|
|
genTypeCheck(InTypes[0], "ain");
|
|
}
|
|
if (OET) {
|
|
genTypeCheck(OET, "aout");
|
|
}
|
|
|
|
// TODO Add the appropriate dimension checking code, as seen in
|
|
// slang_rs_reflection.cpp.
|
|
|
|
std::string FieldPackerName = ef->getName() + "_fp";
|
|
if (ERT) {
|
|
if (genCreateFieldPacker(ERT, FieldPackerName.c_str())) {
|
|
genPackVarOfType(ERT, nullptr, FieldPackerName.c_str());
|
|
}
|
|
}
|
|
mOut.indent() << "forEach(" << slot << ", ";
|
|
|
|
if (ef->hasIns()) {
|
|
// FIXME: Add support for kernels with multiple inputs.
|
|
slangAssert(ef->getIns().size() == 1);
|
|
mOut << "ain, ";
|
|
} else {
|
|
mOut << "NULL, ";
|
|
}
|
|
|
|
if (ef->hasOut() || ef->hasReturn()) {
|
|
mOut << "aout, ";
|
|
} else {
|
|
mOut << "NULL, ";
|
|
}
|
|
|
|
// FIXME (no support for usrData with C++ kernels)
|
|
mOut << "NULL, 0);\n";
|
|
mOut.endBlock();
|
|
}
|
|
}
|
|
|
|
// invoke_* implementation
|
|
void RSReflectionCpp::genExportFunctionBodies() {
|
|
uint32_t slot = 0;
|
|
// Reflect export function
|
|
for (auto I = mRSContext->export_funcs_begin(),
|
|
E = mRSContext->export_funcs_end();
|
|
I != E; I++) {
|
|
const RSExportFunc *ef = *I;
|
|
|
|
makeFunctionSignature(true, ef);
|
|
mOut.startBlock();
|
|
const RSExportRecordType *params = ef->getParamPacketType();
|
|
size_t param_len = 0;
|
|
if (params) {
|
|
param_len = params->getAllocSize();
|
|
if (genCreateFieldPacker(params, "__fp")) {
|
|
genPackVarOfType(params, nullptr, "__fp");
|
|
}
|
|
}
|
|
|
|
mOut.indent() << "invoke(" << slot;
|
|
if (params) {
|
|
mOut << ", __fp.getData(), " << param_len << ");\n";
|
|
} else {
|
|
mOut << ", NULL, 0);\n";
|
|
}
|
|
mOut.endBlock();
|
|
|
|
slot++;
|
|
}
|
|
}
|
|
|
|
bool RSReflectionCpp::genEncodedBitCode() {
|
|
FILE *pfin = fopen(mBitCodeFilePath.c_str(), "rb");
|
|
if (pfin == nullptr) {
|
|
fprintf(stderr, "Error: could not read file %s\n",
|
|
mBitCodeFilePath.c_str());
|
|
return false;
|
|
}
|
|
|
|
unsigned char buf[16];
|
|
int read_length;
|
|
mOut.indent() << "static const unsigned char __txt[] =";
|
|
mOut.startBlock();
|
|
while ((read_length = fread(buf, 1, sizeof(buf), pfin)) > 0) {
|
|
mOut.indent();
|
|
for (int i = 0; i < read_length; i++) {
|
|
char buf2[16];
|
|
snprintf(buf2, sizeof(buf2), "0x%02x,", buf[i]);
|
|
mOut << buf2;
|
|
}
|
|
mOut << "\n";
|
|
}
|
|
mOut.endBlock(true);
|
|
mOut << "\n";
|
|
return true;
|
|
}
|
|
|
|
bool RSReflectionCpp::writeImplementationFile() {
|
|
if (!mOut.startFile(mOutputDirectory, mClassName + ".cpp", mRSSourceFilePath,
|
|
mRSContext->getLicenseNote(), false,
|
|
mRSContext->getVerbose())) {
|
|
return false;
|
|
}
|
|
|
|
// Front matter
|
|
mOut.indent() << "#include \"" << mClassName << ".h\"\n\n";
|
|
|
|
genEncodedBitCode();
|
|
mOut.indent() << "\n\n";
|
|
|
|
// Constructor
|
|
const std::string &packageName = mRSContext->getReflectJavaPackageName();
|
|
mOut.indent() << mClassName << "::" << mClassName
|
|
<< "(android::RSC::sp<android::RSC::RS> rs):\n"
|
|
" ScriptC(rs, __txt, sizeof(__txt), \""
|
|
<< mCleanedRSFileName << "\", " << mCleanedRSFileName.length()
|
|
<< ", \"/data/data/" << packageName << "/app\", sizeof(\""
|
|
<< packageName << "\"))";
|
|
mOut.startBlock();
|
|
for (std::set<std::string>::iterator I = mTypesToCheck.begin(),
|
|
E = mTypesToCheck.end();
|
|
I != E; I++) {
|
|
mOut.indent() << kRsElemPrefix << *I << " = android::RSC::Element::" << *I
|
|
<< "(mRS);\n";
|
|
}
|
|
|
|
for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(),
|
|
E = mRSContext->export_vars_end();
|
|
I != E; I++) {
|
|
const RSExportVar *EV = *I;
|
|
if (!EV->getInit().isUninit()) {
|
|
genInitExportVariable(EV->getType(), EV->getName(), EV->getInit());
|
|
} else {
|
|
genZeroInitExportVariable(EV->getName());
|
|
}
|
|
}
|
|
mOut.endBlock();
|
|
|
|
// Destructor
|
|
mOut.indent() << mClassName << "::~" << mClassName << "()";
|
|
mOut.startBlock();
|
|
mOut.endBlock();
|
|
|
|
// Function bodies
|
|
genExportForEachBodies();
|
|
genExportFunctionBodies();
|
|
|
|
mOut.closeFile();
|
|
return true;
|
|
}
|
|
|
|
void RSReflectionCpp::genExportVariablesGetterAndSetter() {
|
|
mOut.comment("Methods to set and get the variables exported by the script. "
|
|
"Const variables will not have a setter.\n\n"
|
|
"Note that the value returned by the getter may not be the "
|
|
"current value of the variable in the script. The getter will "
|
|
"return the initial value of the variable (as defined in the "
|
|
"script) or the the last value set by using the setter method. "
|
|
"The script is free to modify its value independently.");
|
|
for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(),
|
|
E = mRSContext->export_vars_end();
|
|
I != E; I++) {
|
|
const RSExportVar *EV = *I;
|
|
const RSExportType *ET = EV->getType();
|
|
|
|
switch (ET->getClass()) {
|
|
case RSExportType::ExportClassPrimitive: {
|
|
genGetterAndSetter(static_cast<const RSExportPrimitiveType *>(ET), EV);
|
|
break;
|
|
}
|
|
case RSExportType::ExportClassPointer: {
|
|
// TODO Deprecate this.
|
|
genPointerTypeExportVariable(EV);
|
|
break;
|
|
}
|
|
case RSExportType::ExportClassVector: {
|
|
genGetterAndSetter(static_cast<const RSExportVectorType *>(ET), EV);
|
|
break;
|
|
}
|
|
case RSExportType::ExportClassMatrix: {
|
|
genMatrixTypeExportVariable(EV);
|
|
break;
|
|
}
|
|
case RSExportType::ExportClassConstantArray: {
|
|
genGetterAndSetter(static_cast<const RSExportConstantArrayType *>(ET),
|
|
EV);
|
|
break;
|
|
}
|
|
case RSExportType::ExportClassRecord: {
|
|
genGetterAndSetter(static_cast<const RSExportRecordType *>(ET), EV);
|
|
break;
|
|
}
|
|
default: { slangAssert(false && "Unknown class of type"); }
|
|
}
|
|
}
|
|
}
|
|
|
|
void RSReflectionCpp::genGetterAndSetter(const RSExportPrimitiveType *EPT,
|
|
const RSExportVar *EV) {
|
|
RSReflectionTypeData rtd;
|
|
EPT->convertToRTD(&rtd);
|
|
std::string TypeName = GetTypeName(EPT);
|
|
|
|
if (!EV->isConst()) {
|
|
mOut.indent() << "void set_" << EV->getName() << "(" << TypeName << " v)";
|
|
mOut.startBlock();
|
|
mOut.indent() << "setVar(" << getNextExportVarSlot() << ", ";
|
|
if (EPT->isRSObjectType()) {
|
|
mOut << "v";
|
|
} else {
|
|
mOut << "&v, sizeof(v)";
|
|
}
|
|
mOut << ");\n";
|
|
mOut.indent() << RS_EXPORT_VAR_PREFIX << EV->getName() << " = v;\n";
|
|
mOut.endBlock();
|
|
}
|
|
mOut.indent() << TypeName << " get_" << EV->getName() << "() const";
|
|
mOut.startBlock();
|
|
if (EV->isConst()) {
|
|
const clang::APValue &val = EV->getInit();
|
|
bool isBool = !strcmp(TypeName.c_str(), "bool");
|
|
mOut.indent() << "return ";
|
|
genInitValue(val, isBool);
|
|
mOut << ";\n";
|
|
} else {
|
|
mOut.indent() << "return " << RS_EXPORT_VAR_PREFIX << EV->getName()
|
|
<< ";\n";
|
|
}
|
|
mOut.endBlock();
|
|
}
|
|
|
|
void RSReflectionCpp::genPointerTypeExportVariable(const RSExportVar *EV) {
|
|
const RSExportType *ET = EV->getType();
|
|
|
|
slangAssert((ET->getClass() == RSExportType::ExportClassPointer) &&
|
|
"Variable should be type of pointer here");
|
|
|
|
std::string TypeName = GetTypeName(ET);
|
|
const std::string &VarName = EV->getName();
|
|
|
|
RSReflectionTypeData rtd;
|
|
EV->getType()->convertToRTD(&rtd);
|
|
uint32_t slot = getNextExportVarSlot();
|
|
|
|
if (!EV->isConst()) {
|
|
mOut.indent() << "void bind_" << VarName << "(" << TypeName << " v)";
|
|
mOut.startBlock();
|
|
mOut.indent() << "bindAllocation(v, " << slot << ");\n";
|
|
mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = v;\n";
|
|
mOut.endBlock();
|
|
}
|
|
mOut.indent() << TypeName << " get_" << VarName << "() const";
|
|
mOut.startBlock();
|
|
if (EV->isConst()) {
|
|
const clang::APValue &val = EV->getInit();
|
|
bool isBool = !strcmp(TypeName.c_str(), "bool");
|
|
mOut.indent() << "return ";
|
|
genInitValue(val, isBool);
|
|
mOut << ";\n";
|
|
} else {
|
|
mOut.indent() << "return " << RS_EXPORT_VAR_PREFIX << VarName << ";\n";
|
|
}
|
|
mOut.endBlock();
|
|
}
|
|
|
|
void RSReflectionCpp::genGetterAndSetter(const RSExportVectorType *EVT,
|
|
const RSExportVar *EV) {
|
|
slangAssert(EVT != nullptr);
|
|
|
|
RSReflectionTypeData rtd;
|
|
EVT->convertToRTD(&rtd);
|
|
|
|
if (!EV->isConst()) {
|
|
mOut.indent() << "void set_" << EV->getName() << "("
|
|
<< rtd.type->rs_c_vector_prefix << EVT->getNumElement()
|
|
<< " v)";
|
|
mOut.startBlock();
|
|
mOut.indent() << "setVar(" << getNextExportVarSlot()
|
|
<< ", &v, sizeof(v));\n";
|
|
mOut.indent() << RS_EXPORT_VAR_PREFIX << EV->getName() << " = v;\n";
|
|
mOut.endBlock();
|
|
}
|
|
mOut.indent() << rtd.type->rs_c_vector_prefix << EVT->getNumElement()
|
|
<< " get_" << EV->getName() << "() const";
|
|
mOut.startBlock();
|
|
if (EV->isConst()) {
|
|
const clang::APValue &val = EV->getInit();
|
|
mOut.indent() << "return ";
|
|
genInitValue(val, false);
|
|
mOut << ";\n";
|
|
} else {
|
|
mOut.indent() << "return " << RS_EXPORT_VAR_PREFIX << EV->getName()
|
|
<< ";\n";
|
|
}
|
|
mOut.endBlock();
|
|
}
|
|
|
|
void RSReflectionCpp::genMatrixTypeExportVariable(const RSExportVar *EV) {
|
|
uint32_t slot = getNextExportVarSlot();
|
|
stringstream tmp;
|
|
tmp << slot;
|
|
|
|
const RSExportType *ET = EV->getType();
|
|
if (ET->getName() == "rs_matrix4x4") {
|
|
mOut.indent() << "void set_" << EV->getName() << "(float v[16])";
|
|
mOut.startBlock();
|
|
mOut.indent() << "setVar(" << tmp.str() << ", v, sizeof(float)*16);\n";
|
|
mOut.endBlock();
|
|
} else if (ET->getName() == "rs_matrix3x3") {
|
|
mOut.indent() << "void set_" << EV->getName() << "(float v[9])";
|
|
mOut.startBlock();
|
|
mOut.indent() << "setVar(" << tmp.str() << ", v, sizeof(float)*9);";
|
|
mOut.endBlock();
|
|
} else if (ET->getName() == "rs_matrix2x2") {
|
|
mOut.indent() << "void set_" << EV->getName() << "(float v[4])";
|
|
mOut.startBlock();
|
|
mOut.indent() << "setVar(" << tmp.str() << ", v, sizeof(float)*4);";
|
|
mOut.endBlock();
|
|
} else {
|
|
mOut.indent() << "#error: TODO: " << ET->getName();
|
|
slangAssert(false);
|
|
}
|
|
}
|
|
|
|
void RSReflectionCpp::genGetterAndSetter(const RSExportConstantArrayType *AT,
|
|
const RSExportVar *EV) {
|
|
std::stringstream ArraySpec;
|
|
const RSExportType *ET = EV->getType();
|
|
|
|
const RSExportConstantArrayType *CAT =
|
|
static_cast<const RSExportConstantArrayType *>(ET);
|
|
|
|
uint32_t slot = getNextExportVarSlot();
|
|
stringstream tmp;
|
|
tmp << slot;
|
|
|
|
ArraySpec << CAT->getNumElement();
|
|
mOut.indent() << "void set_" << EV->getName() << "(" << GetTypeName(EV->getType()) << " v "
|
|
<< GetTypeName(EV->getType(), false) << ")";
|
|
mOut.startBlock();
|
|
mOut.indent() << "setVar(" << tmp.str() << ", v, sizeof(" << GetTypeName(EV->getType()) + ") *"
|
|
<< ArraySpec.str() << ");";
|
|
mOut.endBlock();
|
|
}
|
|
|
|
void RSReflectionCpp::genGetterAndSetter(const RSExportRecordType *ERT,
|
|
const RSExportVar *EV) {
|
|
slangAssert(false);
|
|
}
|
|
|
|
void RSReflectionCpp::makeFunctionSignature(bool isDefinition,
|
|
const RSExportFunc *ef) {
|
|
mOut.indent() << "void ";
|
|
if (isDefinition) {
|
|
mOut << mClassName << "::";
|
|
}
|
|
mOut << "invoke_" << ef->getName() << "(";
|
|
|
|
if (ef->getParamPacketType()) {
|
|
bool FirstArg = true;
|
|
for (RSExportFunc::const_param_iterator i = ef->params_begin(),
|
|
e = ef->params_end();
|
|
i != e; i++) {
|
|
if (!FirstArg) {
|
|
mOut << ", ";
|
|
} else {
|
|
FirstArg = false;
|
|
}
|
|
mOut << GetTypeName((*i)->getType()) << " " << (*i)->getName();
|
|
}
|
|
}
|
|
|
|
if (isDefinition) {
|
|
mOut << ")";
|
|
} else {
|
|
mOut << ");\n";
|
|
}
|
|
}
|
|
|
|
void RSReflectionCpp::genArguments(const ArgumentList &Arguments, int Offset) {
|
|
bool FirstArg = true;
|
|
|
|
for (ArgumentList::const_iterator I = Arguments.begin(), E = Arguments.end();
|
|
I != E; I++) {
|
|
if (!FirstArg) {
|
|
mOut << ",\n";
|
|
mOut.indent() << string(Offset, ' ');
|
|
} else {
|
|
FirstArg = false;
|
|
}
|
|
|
|
mOut << I->Type << " " << I->Name;
|
|
if (!I->DefaultValue.empty()) {
|
|
mOut << " = " << I->DefaultValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool RSReflectionCpp::genCreateFieldPacker(const RSExportType *ET,
|
|
const char *FieldPackerName) {
|
|
size_t AllocSize = ET->getAllocSize();
|
|
|
|
if (AllocSize > 0) {
|
|
mOut.indent() << "android::RSC::FieldPacker " << FieldPackerName << "("
|
|
<< AllocSize << ");\n";
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void RSReflectionCpp::genPackVarOfType(const RSExportType *ET,
|
|
const char *VarName,
|
|
const char *FieldPackerName) {
|
|
switch (ET->getClass()) {
|
|
case RSExportType::ExportClassPrimitive:
|
|
case RSExportType::ExportClassVector:
|
|
case RSExportType::ExportClassPointer:
|
|
case RSExportType::ExportClassMatrix: {
|
|
mOut.indent() << FieldPackerName << ".add(" << VarName << ");\n";
|
|
break;
|
|
}
|
|
case RSExportType::ExportClassConstantArray: {
|
|
/*const RSExportConstantArrayType *ECAT =
|
|
static_cast<const RSExportConstantArrayType *>(ET);
|
|
|
|
// TODO(zonr): more elegant way. Currently, we obtain the unique index
|
|
// variable (this method involves recursive call which means
|
|
// we may have more than one level loop, therefore we can't
|
|
// always use the same index variable name here) name given
|
|
// in the for-loop from counting the '.' in @VarName.
|
|
unsigned Level = 0;
|
|
size_t LastDotPos = 0;
|
|
std::string ElementVarName(VarName);
|
|
|
|
while (LastDotPos != std::string::npos) {
|
|
LastDotPos = ElementVarName.find_first_of('.', LastDotPos + 1);
|
|
Level++;
|
|
}
|
|
std::string IndexVarName("ct");
|
|
IndexVarName.append(llvm::utostr(Level));
|
|
|
|
C.indent() << "for (int " << IndexVarName << " = 0; " <<
|
|
IndexVarName << " < " << ECAT->getSize() << "; " <<
|
|
IndexVarName << "++)";
|
|
C.startBlock();
|
|
|
|
ElementVarName.append("[" + IndexVarName + "]");
|
|
genPackVarOfType(C, ECAT->getElementType(), ElementVarName.c_str(),
|
|
FieldPackerName);
|
|
|
|
C.endBlock();*/
|
|
break;
|
|
}
|
|
case RSExportType::ExportClassRecord: {
|
|
const RSExportRecordType *ERT = static_cast<const RSExportRecordType *>(ET);
|
|
// Relative pos from now on in field packer
|
|
unsigned Pos = 0;
|
|
|
|
for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(),
|
|
E = ERT->fields_end();
|
|
I != E; I++) {
|
|
const RSExportRecordType::Field *F = *I;
|
|
std::string FieldName;
|
|
size_t FieldOffset = F->getOffsetInParent();
|
|
const RSExportType *T = F->getType();
|
|
size_t FieldStoreSize = T->getStoreSize();
|
|
size_t FieldAllocSize = T->getAllocSize();
|
|
|
|
if (VarName != nullptr)
|
|
FieldName = VarName + ("." + F->getName());
|
|
else
|
|
FieldName = F->getName();
|
|
|
|
if (FieldOffset > Pos) {
|
|
mOut.indent() << FieldPackerName << ".skip(" << (FieldOffset - Pos)
|
|
<< ");\n";
|
|
}
|
|
|
|
genPackVarOfType(F->getType(), FieldName.c_str(), FieldPackerName);
|
|
|
|
// There is padding in the field type
|
|
if (FieldAllocSize > FieldStoreSize) {
|
|
mOut.indent() << FieldPackerName << ".skip("
|
|
<< (FieldAllocSize - FieldStoreSize) << ");\n";
|
|
}
|
|
|
|
Pos = FieldOffset + FieldAllocSize;
|
|
}
|
|
|
|
// There maybe some padding after the struct
|
|
if (ERT->getAllocSize() > Pos) {
|
|
mOut.indent() << FieldPackerName << ".skip(" << ERT->getAllocSize() - Pos
|
|
<< ");\n";
|
|
}
|
|
break;
|
|
}
|
|
default: { slangAssert(false && "Unknown class of type"); }
|
|
}
|
|
}
|
|
|
|
void RSReflectionCpp::genTypeCheck(const RSExportType *ET,
|
|
const char *VarName) {
|
|
mOut.indent() << "// Type check for " << VarName << "\n";
|
|
|
|
if (ET->getClass() == RSExportType::ExportClassPointer) {
|
|
const RSExportPointerType *EPT =
|
|
static_cast<const RSExportPointerType *>(ET);
|
|
ET = EPT->getPointeeType();
|
|
}
|
|
|
|
std::string TypeName;
|
|
switch (ET->getClass()) {
|
|
case RSExportType::ExportClassPrimitive:
|
|
case RSExportType::ExportClassVector:
|
|
case RSExportType::ExportClassRecord: {
|
|
TypeName = ET->getElementName();
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!TypeName.empty()) {
|
|
mOut.indent() << "if (!" << VarName
|
|
<< "->getType()->getElement()->isCompatible("
|
|
<< kRsElemPrefix << TypeName << "))";
|
|
mOut.startBlock();
|
|
mOut.indent() << "mRS->throwError(RS_ERROR_RUNTIME_ERROR, "
|
|
"\"Incompatible type\");\n";
|
|
mOut.indent() << "return;\n";
|
|
mOut.endBlock();
|
|
}
|
|
}
|
|
|
|
void RSReflectionCpp::genTypeInstanceFromPointer(const RSExportType *ET) {
|
|
if (ET->getClass() == RSExportType::ExportClassPointer) {
|
|
// For pointer parameters to original forEach kernels.
|
|
const RSExportPointerType *EPT =
|
|
static_cast<const RSExportPointerType *>(ET);
|
|
genTypeInstance(EPT->getPointeeType());
|
|
} else {
|
|
// For handling pass-by-value kernel parameters.
|
|
genTypeInstance(ET);
|
|
}
|
|
}
|
|
|
|
void RSReflectionCpp::genTypeInstance(const RSExportType *ET) {
|
|
switch (ET->getClass()) {
|
|
case RSExportType::ExportClassPrimitive:
|
|
case RSExportType::ExportClassVector:
|
|
case RSExportType::ExportClassConstantArray:
|
|
case RSExportType::ExportClassRecord: {
|
|
std::string TypeName = ET->getElementName();
|
|
mTypesToCheck.insert(TypeName);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void RSReflectionCpp::genInitExportVariable(const RSExportType *ET,
|
|
const std::string &VarName,
|
|
const clang::APValue &Val) {
|
|
slangAssert(!Val.isUninit() && "Not a valid initializer");
|
|
|
|
switch (ET->getClass()) {
|
|
case RSExportType::ExportClassPrimitive: {
|
|
const RSExportPrimitiveType *EPT =
|
|
static_cast<const RSExportPrimitiveType *>(ET);
|
|
if (EPT->getType() == DataTypeBoolean) {
|
|
genInitBoolExportVariable(VarName, Val);
|
|
} else {
|
|
genInitPrimitiveExportVariable(VarName, Val);
|
|
}
|
|
break;
|
|
}
|
|
case RSExportType::ExportClassPointer: {
|
|
if (!Val.isInt() || Val.getInt().getSExtValue() != 0)
|
|
std::cerr << "Initializer which is non-NULL to pointer type variable "
|
|
"will be ignored" << std::endl;
|
|
break;
|
|
}
|
|
case RSExportType::ExportClassVector: {
|
|
const RSExportVectorType *EVT = static_cast<const RSExportVectorType *>(ET);
|
|
switch (Val.getKind()) {
|
|
case clang::APValue::Int:
|
|
case clang::APValue::Float: {
|
|
for (unsigned i = 0; i < EVT->getNumElement(); i++) {
|
|
std::string Name = VarName + "." + getVectorAccessor(i);
|
|
genInitPrimitiveExportVariable(Name, Val);
|
|
}
|
|
break;
|
|
}
|
|
case clang::APValue::Vector: {
|
|
unsigned NumElements = std::min(
|
|
static_cast<unsigned>(EVT->getNumElement()), Val.getVectorLength());
|
|
for (unsigned i = 0; i < NumElements; i++) {
|
|
const clang::APValue &ElementVal = Val.getVectorElt(i);
|
|
std::string Name = VarName + "." + getVectorAccessor(i);
|
|
genInitPrimitiveExportVariable(Name, ElementVal);
|
|
}
|
|
break;
|
|
}
|
|
case clang::APValue::MemberPointer:
|
|
case clang::APValue::Uninitialized:
|
|
case clang::APValue::ComplexInt:
|
|
case clang::APValue::ComplexFloat:
|
|
case clang::APValue::LValue:
|
|
case clang::APValue::Array:
|
|
case clang::APValue::Struct:
|
|
case clang::APValue::Union:
|
|
case clang::APValue::AddrLabelDiff: {
|
|
slangAssert(false && "Unexpected type of value of initializer.");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case RSExportType::ExportClassMatrix:
|
|
case RSExportType::ExportClassConstantArray:
|
|
case RSExportType::ExportClassRecord: {
|
|
slangAssert(false && "Unsupported initializer for record/matrix/constant "
|
|
"array type variable currently");
|
|
break;
|
|
}
|
|
default: { slangAssert(false && "Unknown class of type"); }
|
|
}
|
|
}
|
|
|
|
const char *RSReflectionCpp::getVectorAccessor(unsigned Index) {
|
|
static const char *VectorAccessorMap[] = {/* 0 */ "x",
|
|
/* 1 */ "y",
|
|
/* 2 */ "z",
|
|
/* 3 */ "w",
|
|
};
|
|
|
|
slangAssert((Index < (sizeof(VectorAccessorMap) / sizeof(const char *))) &&
|
|
"Out-of-bound index to access vector member");
|
|
|
|
return VectorAccessorMap[Index];
|
|
}
|
|
|
|
void RSReflectionCpp::genZeroInitExportVariable(const std::string &VarName) {
|
|
mOut.indent() << "memset(&" << RS_EXPORT_VAR_PREFIX << VarName
|
|
<< ", 0, sizeof(" << RS_EXPORT_VAR_PREFIX << VarName << "));\n";
|
|
}
|
|
|
|
void
|
|
RSReflectionCpp::genInitPrimitiveExportVariable(const std::string &VarName,
|
|
const clang::APValue &Val) {
|
|
slangAssert(!Val.isUninit() && "Not a valid initializer");
|
|
|
|
mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = ";
|
|
genInitValue(Val);
|
|
mOut << ";\n";
|
|
}
|
|
|
|
void RSReflectionCpp::genInitValue(const clang::APValue &Val, bool asBool) {
|
|
switch (Val.getKind()) {
|
|
case clang::APValue::Int: {
|
|
const llvm::APInt &api = Val.getInt();
|
|
if (asBool) {
|
|
mOut << ((api.getSExtValue() == 0) ? "false" : "true");
|
|
} else {
|
|
// TODO: Handle unsigned correctly for C++
|
|
mOut << api.getSExtValue();
|
|
if (api.getBitWidth() > 32) {
|
|
mOut << "L";
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case clang::APValue::Float: {
|
|
const llvm::APFloat &apf = Val.getFloat();
|
|
llvm::SmallString<30> s;
|
|
apf.toString(s);
|
|
mOut << s.c_str();
|
|
if (&apf.getSemantics() == &llvm::APFloat::IEEEsingle) {
|
|
if (s.count('.') == 0) {
|
|
mOut << ".f";
|
|
} else {
|
|
mOut << "f";
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case clang::APValue::ComplexInt:
|
|
case clang::APValue::ComplexFloat:
|
|
case clang::APValue::LValue:
|
|
case clang::APValue::Vector: {
|
|
slangAssert(false && "Primitive type cannot have such kind of initializer");
|
|
break;
|
|
}
|
|
|
|
default: { slangAssert(false && "Unknown kind of initializer"); }
|
|
}
|
|
}
|
|
|
|
void RSReflectionCpp::genInitBoolExportVariable(const std::string &VarName,
|
|
const clang::APValue &Val) {
|
|
slangAssert(!Val.isUninit() && "Not a valid initializer");
|
|
slangAssert((Val.getKind() == clang::APValue::Int) &&
|
|
"Bool type has wrong initial APValue");
|
|
|
|
mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = "
|
|
<< ((Val.getInt().getSExtValue() == 0) ? "false" : "true")
|
|
<< ";";
|
|
}
|
|
|
|
} // namespace slang
|