Skip to content

Commit

Permalink
Add optional "errormessage" parameter to texture lookup functions. (#686
Browse files Browse the repository at this point in the history
)

OSL's texture(), texture3d(), and environment() functions now take a new
optional argument, "errormessage", followed by string variable
reference. A successful texture lookup will result in storing the empty
string ("") in the variable.

When this option is employed, a failed lookup or other error, such as a
missing texture, will store a non-empty string in the errormessage
variable (usually a descriptive error message, but will be "unknown" if
no message is forthcoming from the TextureSystem, as may be the case if
it's suppressing duplicate error messages from the same file). If the
"errormessage" option is passed, this will be the ONLY way an error is
handled for this call; it will not also forward any errors to the
renderer, assuming that if the shader asks for the message, the shader
intends to fully handle the situation.

If no "errormessage" optional param is passed, behavior is as it always
was: a texture lookup error will be passed to the renderer through the
usual error reporting mechanisms.

The reason for this change is UDIM -- a UDIM set may be sparse, with
some sections of uv space not having concrete texture files that exist.
We don't want those to spew error messages, and our typical way of
checking by doing a query like gettextureinfo(texname,"channels",chans)
is not reliable because it will return the channels for ANY match, doesn't
help you for particular uv ranges.

With this, you can imagine a shader gracefully (and more or less
efficiently) handling a sparse UDIM set with logic that looks like:

    int channels;
    if (gettextureinfo (texturefile, "channels", channels)) {
        string err;
        C = texture (texturefile, u, v, "errormessage", err);
        if (err != "") {
            // texture set exists, but no file for this UDIM section!
            C = missing_udim_color;
        }
    } else {
        // truly nonexistant texture set
        C = error_color;
    }

Unfortunately, this breaks some compatibility with the RendererServices
API. (That's ok, this is for master only, and will not be backported
to release branches because I just can't figure out how to do it without
an API change.) Renderers integrating OSL will need to add new
RendererServices methods texture(), environment(), and texture3d(), which
have an additional ustring* parameter for the error message destination.
Eventually, we'll get rid of the old versions. Allowing both for now will
limit the number of immediate breakages until the renderer authors get
the new calls squared away.
  • Loading branch information
lgritz committed Oct 17, 2016
1 parent 4f85789 commit 9d90766
Show file tree
Hide file tree
Showing 14 changed files with 246 additions and 19 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Expand Up @@ -585,7 +585,8 @@ TESTSUITE ( and-or-not-synonyms aastep arithmetic array array-derivs array-range
ternary
testshade-expr
texture-alpha texture-blur texture-connected-options
texture-derivs texture-firstchannel texture-interp
texture-derivs texture-errormsg
texture-firstchannel texture-interp
texture-missingcolor texture-simple
texture-smallderivs texture-swirl
texture-width texture-withderivs texture-wrap
Expand Down
14 changes: 12 additions & 2 deletions src/doc/languagespec.tex
Expand Up @@ -61,8 +61,8 @@
Editor: Larry Gritz \\
\emph{lg@imageworks.com}
}
\date{{\large Date: 14 Jan, 2016 \\
(with corrections, 27 Sep 2016)
\date{{\large Date: 13 Oct, 2016 \\
% (with corrections, 27 Sep 2016)
}
\bigskip
\bigskip
Expand Down Expand Up @@ -3992,6 +3992,16 @@ \section{Texture}
\apiend
\vspace{-16pt}

\apiitem{"errormessage", <stringvariable>}
\vspace{12pt}
\NEW % 1.8
If this option is supplied, any error messages generated by the texture
system will be stored in the specified variable rather than issuing error
calls to the renderer, thus leaving it up to the shader to handle any
errors. The error message stored will be \qkw{} if no error occurred.
\apiend
\vspace{-16pt}

\apiitem{"interp", <string>}
\vspace{12pt}
Overrides the texture interpolation method: \qkw{smartcubic} (the
Expand Down
49 changes: 49 additions & 0 deletions src/include/OSL/rendererservices.h
Expand Up @@ -230,6 +230,22 @@ class OSLEXECPUBLIC RendererServices {
///
/// Return true if the file is found and could be opened, otherwise
/// return false.
///
/// If the errormessage parameter is NULL, this method is expected to
/// handle the errors fully, including forwarding them to the renderer
/// or shading system. If errormessage is non-NULL, any resulting error
/// messages (in case of failure, when the function returns false) will
/// be stored there, leaving it up to the caller/shader to handle the
/// error.
virtual bool texture (ustring filename, TextureHandle *texture_handle,
TexturePerthread *texture_thread_info,
TextureOpt &options, ShaderGlobals *sg,
float s, float t, float dsdx, float dtdx,
float dsdy, float dtdy, int nchannels,
float *result, float *dresultds, float *dresultdt,
ustring *errormessage);
// Deprecated version, with no errormessage parameter. This will
// eventually disappear.
virtual bool texture (ustring filename, TextureHandle *texture_handle,
TexturePerthread *texture_thread_info,
TextureOpt &options, ShaderGlobals *sg,
Expand All @@ -255,6 +271,23 @@ class OSLEXECPUBLIC RendererServices {
///
/// Return true if the file is found and could be opened, otherwise
/// return false.
///
/// If the errormessage parameter is NULL, this method is expected to
/// handle the errors fully, including forwarding them to the renderer
/// or shading system. If errormessage is non-NULL, any resulting error
/// messages (in case of failure, when the function returns false) will
/// be stored there, leaving it up to the caller/shader to handle the
/// error.
virtual bool texture3d (ustring filename, TextureHandle *texture_handle,
TexturePerthread *texture_thread_info,
TextureOpt &options, ShaderGlobals *sg,
const Vec3 &P, const Vec3 &dPdx, const Vec3 &dPdy,
const Vec3 &dPdz, int nchannels,
float *result, float *dresultds,
float *dresultdt, float *dresultdr,
ustring *errormessage);
// Deprecated version, with no errormessage parameter. This will
// eventually disappear.
virtual bool texture3d (ustring filename, TextureHandle *texture_handle,
TexturePerthread *texture_thread_info,
TextureOpt &options, ShaderGlobals *sg,
Expand All @@ -278,6 +311,22 @@ class OSLEXECPUBLIC RendererServices {
///
/// Return true if the file is found and could be opened, otherwise
/// return false.
///
/// If the errormessage parameter is NULL, this method is expected to
/// handle the errors fully, including forwarding them to the renderer
/// or shading system. If errormessage is non-NULL, any resulting error
/// messages (in case of failure, when the function returns false) will
/// be stored there, leaving it up to the caller/shader to handle the
/// error.
virtual bool environment (ustring filename, TextureHandle *texture_handle,
TexturePerthread *texture_thread_info,
TextureOpt &options, ShaderGlobals *sg,
const Vec3 &R, const Vec3 &dRdx, const Vec3 &dRdy,
int nchannels, float *result,
float *dresultds, float *dresultdt,
ustring *errormessage);
// Deprecated version, with no errormessage parameter. This will
// eventually disappear.
virtual bool environment (ustring filename, TextureHandle *texture_handle,
TexturePerthread *texture_thread_info,
TextureOpt &options, ShaderGlobals *sg,
Expand Down
2 changes: 1 addition & 1 deletion src/liboslcomp/typecheck.cpp
Expand Up @@ -1003,7 +1003,7 @@ ASTfunction_call::typecheck_printf_args (const char *format, ASTNode *arg)
void
ASTfunction_call::typecheck_builtin_specialcase ()
{
const char *tex_out_args[] = {"alpha", NULL};
const char *tex_out_args[] = {"alpha", "errormessage", NULL};
const char *pointcloud_out_args[] = {"*", NULL};

if (m_name == "transform") {
Expand Down
6 changes: 3 additions & 3 deletions src/liboslexec/builtindecl.h
Expand Up @@ -374,9 +374,9 @@ DECL (osl_texture_set_subimage, "xXi")
DECL (osl_texture_set_subimagename, "xXs")
DECL (osl_texture_set_missingcolor_arena, "xXX")
DECL (osl_texture_set_missingcolor_alpha, "xXif")
DECL (osl_texture, "iXXXXffffffiXXXXXX")
DECL (osl_texture3d, "iXXXXXXXXiXXXXXXXX")
DECL (osl_environment, "iXXXXXXXiXXXXXX")
DECL (osl_texture, "iXXXXffffffiXXXXXXX")
DECL (osl_texture3d, "iXXXXXXXXiXXXXXXXXX")
DECL (osl_environment, "iXXXXXXXiXXXXXXX")
DECL (osl_get_textureinfo, "iXXXXiiiX")

DECL (osl_trace_set_mindist, "xXf")
Expand Down
19 changes: 14 additions & 5 deletions src/liboslexec/llvm_gen.cpp
Expand Up @@ -1997,7 +1997,7 @@ static llvm::Value *
llvm_gen_texture_options (BackendLLVM &rop, int opnum,
int first_optional_arg, bool tex3d, int nchans,
llvm::Value* &alpha, llvm::Value* &dalphadx,
llvm::Value* &dalphady)
llvm::Value* &dalphady, llvm::Value* &errormessage)
{
llvm::Value* opt = rop.ll.call_function ("osl_get_texture_options",
rop.sg_void_ptr());
Expand Down Expand Up @@ -2141,7 +2141,10 @@ llvm_gen_texture_options (BackendLLVM &rop, int opnum,
// NO z derivs! dalphadz = rop.llvm_get_pointer (Val, 3);
}
continue;

}
if (name == Strings::errormessage && valtype == TypeDesc::STRING) {
errormessage = rop.llvm_get_pointer (Val);
continue;
}
if (name == Strings::missingcolor &&
equivalent(valtype,TypeDesc::TypeColor)) {
Expand Down Expand Up @@ -2218,9 +2221,10 @@ LLVMGEN (llvm_gen_texture)

llvm::Value* opt; // TextureOpt
llvm::Value *alpha = NULL, *dalphadx = NULL, *dalphady = NULL;
llvm::Value *errormessage = NULL;
opt = llvm_gen_texture_options (rop, opnum, first_optional_arg,
false /*3d*/, nchans,
alpha, dalphadx, dalphady);
alpha, dalphadx, dalphady, errormessage);

// Now call the osl_texture function, passing the options and all the
// explicit args like texture coordinates.
Expand Down Expand Up @@ -2258,6 +2262,7 @@ LLVMGEN (llvm_gen_texture)
args.push_back (rop.ll.void_ptr (alpha ? alpha : rop.ll.void_ptr_null()));
args.push_back (rop.ll.void_ptr (dalphadx ? dalphadx : rop.ll.void_ptr_null()));
args.push_back (rop.ll.void_ptr (dalphady ? dalphady : rop.ll.void_ptr_null()));
args.push_back (rop.ll.void_ptr (errormessage ? errormessage : rop.ll.void_ptr_null()));
rop.ll.call_function ("osl_texture", &args[0], (int)args.size());
rop.generated_texture_call (texture_handle != NULL);
return true;
Expand All @@ -2284,9 +2289,10 @@ LLVMGEN (llvm_gen_texture3d)

llvm::Value* opt; // TextureOpt
llvm::Value *alpha = NULL, *dalphadx = NULL, *dalphady = NULL;
llvm::Value *errormessage = NULL;
opt = llvm_gen_texture_options (rop, opnum, first_optional_arg,
true /*3d*/, nchans,
alpha, dalphadx, dalphady);
alpha, dalphadx, dalphady, errormessage);

// Now call the osl_texture3d function, passing the options and all the
// explicit args like texture coordinates.
Expand Down Expand Up @@ -2333,6 +2339,7 @@ LLVMGEN (llvm_gen_texture3d)
args.push_back (rop.ll.void_ptr (dalphadx ? dalphadx : rop.ll.void_ptr_null()));
args.push_back (rop.ll.void_ptr (dalphady ? dalphady : rop.ll.void_ptr_null()));
args.push_back (rop.ll.void_ptr_null()); // No dalphadz for now
args.push_back (rop.ll.void_ptr (errormessage ? errormessage : rop.ll.void_ptr_null()));
rop.ll.call_function ("osl_texture3d", &args[0], (int)args.size());
rop.generated_texture_call (texture_handle != NULL);
return true;
Expand All @@ -2358,9 +2365,10 @@ LLVMGEN (llvm_gen_environment)

llvm::Value* opt; // TextureOpt
llvm::Value *alpha = NULL, *dalphadx = NULL, *dalphady = NULL;
llvm::Value *errormessage = NULL;
opt = llvm_gen_texture_options (rop, opnum, first_optional_arg,
false /*3d*/, nchans,
alpha, dalphadx, dalphady);
alpha, dalphadx, dalphady, errormessage);

// Now call the osl_environment function, passing the options and all the
// explicit args like texture coordinates.
Expand Down Expand Up @@ -2399,6 +2407,7 @@ LLVMGEN (llvm_gen_environment)
args.push_back (rop.ll.void_ptr_null());
args.push_back (rop.ll.void_ptr_null());
}
args.push_back (rop.ll.void_ptr (errormessage ? errormessage : rop.ll.void_ptr_null()));
rop.ll.call_function ("osl_environment", &args[0], (int)args.size());
rop.generated_texture_call (texture_handle != NULL);
return true;
Expand Down
25 changes: 19 additions & 6 deletions src/liboslexec/optexture.cpp
Expand Up @@ -249,7 +249,8 @@ osl_texture (void *sg_, const char *name, void *handle,
void *opt_, float s, float t,
float dsdx, float dtdx, float dsdy, float dtdy,
int chans, void *result, void *dresultdx, void *dresultdy,
void *alpha, void *dalphadx, void *dalphady)
void *alpha, void *dalphadx, void *dalphady,
ustring *errormessage)
{
ShaderGlobals *sg = (ShaderGlobals *)sg_;
TextureOpt *opt = (TextureOpt *)opt_;
Expand All @@ -262,7 +263,8 @@ osl_texture (void *sg_, const char *name, void *handle,
*opt, sg, s, t, dsdx, dtdx, dsdy, dtdy, 4,
(float *)&result_simd,
derivs ? (float *)&dresultds_simd : NULL,
derivs ? (float *)&dresultdt_simd : NULL);
derivs ? (float *)&dresultdt_simd : NULL,
errormessage);

for (int i = 0; i < chans; ++i)
((float *)result)[i] = result_simd[i];
Expand All @@ -283,6 +285,8 @@ osl_texture (void *sg_, const char *name, void *handle,
}
}

if (ok && errormessage)
*errormessage = Strings::_emptystring_;
return ok;
}

Expand All @@ -295,7 +299,8 @@ osl_texture3d (void *sg_, const char *name, void *handle,
void *result, void *dresultdx,
void *dresultdy, void *dresultdz,
void *alpha, void *dalphadx,
void *dalphady, void *dalphadz)
void *dalphady, void *dalphadz,
ustring *errormessage)
{
const Vec3 &P (*(Vec3 *)P_);
const Vec3 &dPdx (*(Vec3 *)dPdx_);
Expand All @@ -313,7 +318,8 @@ osl_texture3d (void *sg_, const char *name, void *handle,
4, (float *)&result_simd,
derivs ? (float *)&dresultds_simd : NULL,
derivs ? (float *)&dresultdt_simd : NULL,
derivs ? (float *)&dresultdr_simd : NULL);
derivs ? (float *)&dresultdr_simd : NULL,
errormessage);

for (int i = 0; i < chans; ++i)
((float *)result)[i] = result_simd[i];
Expand All @@ -339,6 +345,9 @@ osl_texture3d (void *sg_, const char *name, void *handle,
((float *)dalphadz)[0] = dresultdz_simd[chans];
}
}

if (ok && errormessage)
*errormessage = Strings::_emptystring_;
return ok;
}

Expand All @@ -349,7 +358,8 @@ osl_environment (void *sg_, const char *name, void *handle,
void *opt_, void *R_,
void *dRdx_, void *dRdy_, int chans,
void *result, void *dresultdx, void *dresultdy,
void *alpha, void *dalphadx, void *dalphady)
void *alpha, void *dalphadx, void *dalphady,
ustring *errormessage)
{
const Vec3 &R (*(Vec3 *)R_);
const Vec3 &dRdx (*(Vec3 *)dRdx_);
Expand All @@ -362,7 +372,8 @@ osl_environment (void *sg_, const char *name, void *handle,
bool ok = sg->renderer->environment (USTR(name),
(TextureSystem::TextureHandle *)handle,
NULL, *opt, sg, R, dRdx, dRdy, 4,
(float *)&local_result, NULL, NULL);
(float *)&local_result, NULL, NULL,
errormessage);

for (int i = 0; i < chans; ++i)
((float *)result)[i] = local_result[i];
Expand All @@ -389,6 +400,8 @@ osl_environment (void *sg_, const char *name, void *handle,
((float *)dalphady)[0] = 0.0f;
}

if (ok && errormessage)
*errormessage = Strings::_emptystring_;
return ok;
}

Expand Down
4 changes: 3 additions & 1 deletion src/liboslexec/oslexec_pvt.h
Expand Up @@ -94,7 +94,7 @@ namespace Strings {
extern ustring blur, sblur, tblur, rblur;
extern ustring wrap, swrap, twrap, rwrap;
extern ustring black, clamp, periodic, mirror;
extern ustring firstchannel, fill, alpha;
extern ustring firstchannel, fill, alpha, errormessage;
extern ustring interp, closest, linear, cubic, smartcubic;
extern ustring perlin, uperlin, noise, snoise, pnoise, psnoise;
extern ustring cell, cellnoise, pcellnoise;
Expand All @@ -109,6 +109,8 @@ namespace Strings {
extern ustring unull;
extern ustring raytype;
extern ustring color, point, vector, normal, matrix;
extern ustring unknown;
extern ustring _emptystring_;
}; // namespace Strings


Expand Down

0 comments on commit 9d90766

Please sign in to comment.