From 3b2818b2aa34f770df336349adf7c0f27ad65654 Mon Sep 17 00:00:00 2001 From: Ole Gulbrandsen Date: Wed, 17 Nov 2021 15:45:29 -0800 Subject: [PATCH] Extend gettextureinfo to read arbitrary arrays and output their size if matching basetype and fit inside the destination array. --- src/include/OSL/rendererservices.h | 7 +++ src/liboslcomp/typecheck.cpp | 11 +++-- src/liboslexec/builtindecl.h | 5 ++- src/liboslexec/constfold.cpp | 72 +++++++++++++++++++++++++++++- src/liboslexec/llvm_gen.cpp | 32 ++++++++++--- src/liboslexec/optexture.cpp | 50 +++++++++++++++++++++ src/liboslexec/rendservices.cpp | 29 ++++++++++++ 7 files changed, 192 insertions(+), 14 deletions(-) diff --git a/src/include/OSL/rendererservices.h b/src/include/OSL/rendererservices.h index 602a8ff08..ba203c109 100644 --- a/src/include/OSL/rendererservices.h +++ b/src/include/OSL/rendererservices.h @@ -329,6 +329,13 @@ class OSLEXECPUBLIC RendererServices { void *data, ustring *errormessage); + virtual bool get_texture_info_type (ustring filename, + TextureHandle *texture_handle, + TexturePerthread *texture_thread_info, + ShadingContext *shading_context, + int subimage, + ustring dataname, TypeDesc &datatype, + ustring *errormessage); /// Lookup nearest points in a point cloud. It will search for /// points around the given center within the specified radius. A diff --git a/src/liboslcomp/typecheck.cpp b/src/liboslcomp/typecheck.cpp index 564dc99c5..63defdc70 100644 --- a/src/liboslcomp/typecheck.cpp +++ b/src/liboslcomp/typecheck.cpp @@ -1272,10 +1272,15 @@ ASTfunction_call::typecheck_builtin_specialcase() argwriteonly(1); argwriteonly(2); } else if (m_name == "getattribute" || m_name == "getmessage" - || m_name == "gettextureinfo" || m_name == "getmatrix" - || m_name == "dict_value") { + || m_name == "getmatrix" || m_name == "dict_value") { // these all write to their last argument argwriteonly(nargs); + } else if (m_name == "gettextureinfo") { + argwriteonly(nargs); + // also write to the second last argument if we're looking + // up an array and querying the arraylength + if (nargs == 4) + argwriteonly(3); } else if (m_name == "pointcloud_get") { argwriteonly(5); } else if (m_name == "pointcloud_search") { @@ -2136,7 +2141,7 @@ static const char * builtin_func_args [] = { "fprintf", "xss*", "!printf", NULL, "getattribute", "is?", "is?[]", "iss?", "iss?[]", "isi?", "isi?[]", "issi?", "issi?[]", "!rw", NULL, // FIXME -- further checking? "getmessage", "is?", "is?[]", "iss?", "iss?[]", "!rw", NULL, - "gettextureinfo", "iss?", "iss?[]", "isffs?", "isffs?[]", "!rw", NULL, // FIXME -- further checking? + "gettextureinfo", "iss?", "iss?[]", "isffs?", "isffs?[]", "issi?[]", "!rw", NULL, // FIXME -- further checking? "hashnoise", NOISE_ARGS, NULL, "isconnected", "i?", NULL, "isconstant", "i?", NULL, diff --git a/src/liboslexec/builtindecl.h b/src/liboslexec/builtindecl.h index c5124f967..5bd410082 100644 --- a/src/liboslexec/builtindecl.h +++ b/src/liboslexec/builtindecl.h @@ -366,8 +366,9 @@ DECL (osl_texture_set_missingcolor_alpha, "xXif") DECL (osl_texture, "iXXXXffffffiXXXXXXX") DECL (osl_texture3d, "iXXXXXXXiXXXXXXX") DECL (osl_environment, "iXXXXXXXiXXXXXXX") -DECL (osl_get_textureinfo, "iXXXXiiiXX") -DECL (osl_get_textureinfo_st, "iXXXffXiiiXX") +DECL (osl_get_textureinfo, "iXXXXiiiXX") +DECL (osl_get_textureinfo_st, "iXXXffXiiiXX") +DECL (osl_get_textureinfo_array, "iXXXXXiiiXX") DECL (osl_trace_set_mindist, "xXf") DECL (osl_trace_set_maxdist, "xXf") diff --git a/src/liboslexec/constfold.cpp b/src/liboslexec/constfold.cpp index aea6321fd..b05d37fd1 100644 --- a/src/liboslexec/constfold.cpp +++ b/src/liboslexec/constfold.cpp @@ -2330,15 +2330,83 @@ DECLFOLDER(constfold_gettextureinfo) if (use_coords) return 0; + // This is the case where we're querying an arbitrary array and return + // its data and array-length + bool use_datalen = (op.nargs() == 5); + OSL_MAYBE_UNUSED Symbol& Result(*rop.inst()->argsymbol(op.firstarg() + 0)); Symbol &Filename (*rop.inst()->argsymbol(op.firstarg()+1)); Symbol &Dataname (*rop.inst()->argsymbol(op.firstarg() + (use_coords ? 4 : 2))); - Symbol &Data (*rop.inst()->argsymbol(op.firstarg() + (use_coords ? 5 : 3))); + Symbol *Datalen (use_datalen ? rop.inst()->argsymbol(op.firstarg()+3) : nullptr); + Symbol &Data (*rop.inst()->argsymbol(op.firstarg() + (use_coords ? 5 : 3 + use_datalen))); OSL_DASSERT (Result.typespec().is_int() && Filename.typespec().is_string() && Dataname.typespec().is_string()); - if (Filename.is_constant() && Dataname.is_constant()) { + if (Datalen && Filename.is_constant() && Dataname.is_constant()) { + // This is the constant folding version of osl_get_textureinfo_array. + // It is less strict than the regular osl_get_textureinfo: as long + // as "data" is of the right basetype and large enough to fit the data stored + // under "dataname", we fill up data. + // + // Here we don't recreate TypeDesc of data - we first fill it with the TypeDesc + // for the dataname we're interested in, we then check that we have enough + // space (and the right type) to store it, and then we pretend our output + // "data" has the same datatype. + ustring filename = Filename.get_string(); + ustring dataname = Dataname.get_string(); + TypeDesc t = Data.typespec().simpletype(); + void *mydata = OIIO_ALLOCA(char, t.size()); + + ustring errormessage; + + TypeDesc typedesc; + int result = rop.renderer()->get_texture_info_type (filename, nullptr, + rop.shadingcontext()->texture_thread_info(), + rop.shadingcontext(), + 0 /* TODO: subimage? */, + dataname, typedesc, &errormessage); + + bool valid_destination = ((t.arraylen >= typedesc.arraylen) && + (t.basetype == typedesc.basetype) && + (t.aggregate == typedesc.aggregate)); + + if (result && valid_destination){ + result = rop.renderer()->get_texture_info (filename, nullptr, + rop.shadingcontext()->texture_thread_info(), + rop.shadingcontext(), + 0 /* TODO: subimage? */, + dataname, typedesc, mydata, &errormessage); + + // If we failed to read the data, we should bail out here, and leave all + // the output variables untouched. + if (!result) + return 0; + + int oldresultarg = rop.inst()->args()[op.firstarg()+0]; + int datalenarg = rop.inst()->args()[op.firstarg()+3]; + int dataarg = rop.inst()->args()[op.firstarg()+4]; + + // Make data the first argument + rop.inst()->args()[op.firstarg()+0] = dataarg; + // Now turn it into an assignment + int cind = rop.add_constant (Data.typespec(), mydata); + rop.turn_into_assign (op, cind, "const fold gettextureinfo"); + + // Now insert a new instruction that assigns 1 to the + // original return result of gettextureinfo. + int one = 1; + rop.insert_code (opnum, u_assign, {oldresultarg, rop.add_constant (TypeDesc::TypeInt, &one)}, + RuntimeOptimizer::RecomputeRWRanges, + RuntimeOptimizer::GroupWithNext); + + // We also insert an instruction that assigns the datalen value + rop.insert_code (opnum, u_assign, {datalenarg, rop.add_constant(typedesc.arraylen)}, + RuntimeOptimizer::RecomputeRWRanges, + RuntimeOptimizer::GroupWithNext); + return 1; + } + }else if (Filename.is_constant() && Dataname.is_constant()) { ustring filename = Filename.get_string(); ustring dataname = Dataname.get_string(); TypeDesc t = Data.typespec().simpletype(); diff --git a/src/liboslexec/llvm_gen.cpp b/src/liboslexec/llvm_gen.cpp index c687b7098..eedfb65f6 100644 --- a/src/liboslexec/llvm_gen.cpp +++ b/src/liboslexec/llvm_gen.cpp @@ -3014,21 +3014,25 @@ LLVMGEN (llvm_gen_gettextureinfo) { Opcode &op (rop.inst()->ops()[opnum]); - OSL_DASSERT(op.nargs() == 4 || op.nargs() == 6); + OSL_DASSERT(op.nargs() == 4 || op.nargs() == 5 || op.nargs() == 6); bool use_coords = (op.nargs() == 6); + bool use_datalen = (op.nargs() == 5); Symbol& Result = *rop.opargsym (op, 0); Symbol& Filename = *rop.opargsym (op, 1); - Symbol& Dataname = *rop.opargsym (op, use_coords ? 4 : 2); - Symbol& Data = *rop.opargsym (op, use_coords ? 5 : 3); + Symbol* S = use_coords ? rop.opargsym(op, 2) : nullptr; Symbol* T = use_coords ? rop.opargsym(op, 3) : nullptr; + Symbol& Dataname = *rop.opargsym (op, use_coords ? 4 : 2); + Symbol* Datalen = use_datalen ? rop.opargsym (op, 3) : nullptr; + Symbol& Data = *rop.opargsym (op, use_coords ? 5 : 3 + use_datalen); OSL_DASSERT(!Result.typespec().is_closure_based() && Filename.typespec().is_string() && (S == nullptr || S->typespec().is_float()) && (T == nullptr || T->typespec().is_float()) && + (Datalen == nullptr || Datalen->typespec().is_int()) && Dataname.typespec().is_string() && - !Data.typespec().is_closure_based() && + !Data.typespec().is_closure_based() && Result.typespec().is_int()); RendererServices::TextureHandle *texture_handle = NULL; @@ -3040,22 +3044,36 @@ LLVMGEN (llvm_gen_gettextureinfo) args.push_back(rop.sg_void_ptr()); args.push_back(rop.llvm_load_value (Filename)); args.push_back(rop.ll.constant_ptr (texture_handle)); + if (use_coords) { args.push_back(rop.llvm_load_value(*S)); args.push_back(rop.llvm_load_value(*T)); } + args.push_back(rop.llvm_load_value(Dataname)); + + if (use_datalen) + args.push_back(rop.llvm_void_ptr(*Datalen)); + // this passes a TypeDesc to an LLVM op-code args.push_back(rop.ll.constant((int) Data.typespec().simpletype().basetype)); args.push_back(rop.ll.constant((int) Data.typespec().simpletype().arraylen)); args.push_back(rop.ll.constant((int) Data.typespec().simpletype().aggregate)); + + // destination args.push_back(rop.llvm_void_ptr (Data)); // errormessage args.push_back(rop.ll.void_ptr_null()); - llvm::Value* r = rop.ll.call_function(use_coords ? "osl_get_textureinfo_st" - : "osl_get_textureinfo", - args); + llvm::Value* r = nullptr; + + if (use_coords) + r = rop.ll.call_function("osl_get_textureinfo_st", args); + else if (use_datalen) + r = rop.ll.call_function("osl_get_textureinfo_array", args); + else + r = rop.ll.call_function("osl_get_textureinfo", args); + rop.llvm_store_value (r, Result); /* Do not leave derivs uninitialized */ if (Data.has_derivs()) diff --git a/src/liboslexec/optexture.cpp b/src/liboslexec/optexture.cpp index 86dca8425..7cc8a0f00 100644 --- a/src/liboslexec/optexture.cpp +++ b/src/liboslexec/optexture.cpp @@ -403,6 +403,56 @@ osl_get_textureinfo (void *sg_, const char *name, void *handle, errormessage); } +OSL_SHADEOP int +osl_get_textureinfo_array (void *sg_, const char *name, void *handle, + void *dataname, void *datalen, int type, + int arraylen, int aggregate, void *data, + ustring *errormessage) +{ + // This function is less strict than the regular osl_get_textureinfo: as long + // as "data" is of the right basetype and large enough to fit the data stored + // under "dataname", we fill up data. + // + // Here we don't recreate TypeDesc of data - we first fill it with the TypeDesc + // for the dataname we're interested in, we then check that we have enough + // space (and the right type) to store it, and then we pretend our output + // "data" has the same datatype. + TypeDesc typedesc; + + ShaderGlobals *sg = (ShaderGlobals *)sg_; + + int result = sg->renderer->get_texture_info_type (USTR(name), + (RendererServices::TextureHandle *)handle, + sg->context->texture_thread_info(), + sg->context, + 0 /*FIXME-ptex*/, + USTR(dataname), typedesc, + errormessage); + + bool valid_destination = ((arraylen >= typedesc.arraylen) && + (type == typedesc.basetype) && + (aggregate == typedesc.aggregate)); + + if (result && valid_destination){ + + result = sg->renderer->get_texture_info (USTR(name), + (RendererServices::TextureHandle *)handle, + sg->context->texture_thread_info(), + sg->context, + 0 /*FIXME-ptex*/, + USTR(dataname), typedesc, data, + errormessage); + // In the spirit of other get_texture_info/get_attribute calls, we try + // to leave any output variables untouched if we fail, so we have to + // check we could actually read the data before settign the length. + if (result) { + *(int*)datalen = typedesc.arraylen; + return true; + } + } + return false; +} + OSL_SHADEOP int diff --git a/src/liboslexec/rendservices.cpp b/src/liboslexec/rendservices.cpp index fe3811919..41d4c91ee 100644 --- a/src/liboslexec/rendservices.cpp +++ b/src/liboslexec/rendservices.cpp @@ -247,6 +247,35 @@ RendererServices::get_texture_info (ustring filename, } +bool +RendererServices::get_texture_info_type (ustring filename, + TextureHandle *texture_handle, + TexturePerthread *texture_thread_info, + ShadingContext *shading_context, + int subimage, ustring dataname, + TypeDesc &datatype, ustring *errormessage) +{ + if (! texture_thread_info) + texture_thread_info = shading_context->texture_thread_info(); + if (! texture_handle) + texture_handle = texturesys()->get_texture_handle (filename, texture_thread_info); + bool status = texturesys()->get_texture_info_type (texture_handle, texture_thread_info, subimage, + dataname, datatype); + if (!status) { + std::string err = texturesys()->geterror(); + if (err.size()) { + if (errormessage) { + *errormessage = ustring(err); + } else { + shading_context->errorf("[RendererServices::get_texture_info] %s", err); + } + } else if (errormessage) { + // gettextureinfo failed but did not provide an error, so none should be emitted + *errormessage = ustring(); + } + } + return status; +} bool RendererServices::get_texture_info(ustring filename,