From 6441f10dfac294036e9fb35a13539e053916eb0b Mon Sep 17 00:00:00 2001 From: Steena Monteiro Date: Wed, 21 Jun 2023 17:04:17 -0700 Subject: [PATCH] Add new customization points in RendererServices for reporting errors, warnings, printf, and fprintf. These customization points accept a fmtlib style format specifier (vs. printf style) whose argument types are represented as EncodedTypes (encodedtypes.h) and can be subsequently decoded via a utility function. Removes dependence on ShadingContext and OSL::ErrorHandler for logging error, warning, printf, and fprintf calls for use on CPU and device during Shader execution. ShadingContext and OSL::ErrorHandler remain utilized during shader compilation/JIT. Journal Buffer approach: each thread gets its own chain of pages within the shared journal buffer for recording errors, warnings, etc. By maintaining a separate chain per thread we can record errors (etc.) in a non-blocking fashion. Shade index is recorded for use by error reporter to sort messages but it is not used at present. Using a Journal buffer is up to a Renderer. The Renderer use the new customization points (rs_errorfmt, rs_filefmt, rs_printfmt, rs_warningfmt or their virtual function equivalents) to interact with a journal::Writer and journal buffer owned by its RenderState. The Renderer would of have to allocate and initialized the journal buffer with the requested page size and number of threads before executing a shader. After a shader is done executing, the contents of the journal buffer can be transfered back to the host and processed with a journal::Reader, which reports them through a journal::Reporter's virtual interface. Intent is for Renderers's to use the Journal buffer and provide their own overriden version of the journal::Reporter. Testshade provides example usage. For legacy purposes, the default virtual RendererServices will route errors to ShadingSystem's OSL::ErrorHandler, but intent is for Renderer's to switch over to using a Journal buffer or their own custom logging. NOTE: OSL library functions as well use Renderer Service free functions can directly call OSL::filefmt, OSL::printfmt, OSL::errorfmt, OSL::warningfmt which wrappers to the underlying free functions (who may record the messages into a journal buffer). Added a new hashcode datatype in typespec.cpp; represented as "h" in function arguments in builtindecl. To print closures added a new OSL function osl_closure_to_ustringhash to return a ustringhash_pod value directly. Shader execute functions now require a zero-based thread_index to identify the calling thread; used for journalling. RendererServices::get_texture_info parameter ShadingContext * changed to ShaderGlobals * (aka ExecutionContext). ShaderGlobals now tracks both shade_index and thread_index. As we look to hide/remove ShaderGlobals in the future, we still need a context object to replace the role the ShaderGlobals struct is currently serving (just minus the actual shader global variables). As a first step towards this goal, we introduce the concept of an ExecutionContext and OpaqueExecutionContext. These just alias to ShaderGlobals currently, but start to establish the idea of hiding its contents. Instead of direct memory access to the ExecutionContext/ShaderGlobals new getter functions have been added that accept an OpaqueExecutionContext and provide the requested data. When inlined there should be no performance penalty, and reliance on the ShaderGlobals implementation detail will be reduced. IE: inline const Vec3 & get_P(OpaqueExecContextPtr oec); template RenderStateT* get_rs(OpaqueExecContextPtr oec); inline int get_raytype(OpaqueExecContextPtr oec); Updated free function renderer services and opcolor to use the ExecContext, but left the rest alone to minimize size of this PR. We introduce opfmt.cpp that provides shim function for llvm_gen to call, where the shim adapts datatypes from llvm to c++ forwarding calls to the free function renderer service error, warning, print, fileprint functions. Split llvm_gen_printf into llvm_gen_printf_legacy, for string format calls or when using optix, and the new llvm_gen_print_fmt which will convert the printf style specifier to the fmtlib format that the Renderer Service customization points are expecting. fprintf by default no longer writes out to a file, is routed to journal::Reporter::report_file_print which could be overriden (example in TestShade to maintain existing behavior). However for security reasons, we do not recommend allowing OSL shader's direct file system but instead just an annotated log entry. To maintain existing behavior of disallowing output of repeated errors/warnings over a history window, we have provided 2 classes that could be used during reporting: TrackRecentlyReported and Report2ErrorHandler. TrackRecentlyReported can turn on/off limitting errors and warnings and control the history capacity. Report2ErrorHandler simply reports errors to an existing OSL::ErrorHandler to allow for easy integration. However we expect Renderers to not use Report2ErrorHandler and provide their own to directly interact with their logging systems. Signed-off-by: Steena Monteiro --- src/cmake/compiler.cmake | 5 - src/cmake/testing.cmake | 14 + src/include/OSL/encodedtypes.h | 214 ++++-- src/include/OSL/fmt_util.h | 134 ++++ src/include/OSL/journal.h | 364 ++++++++++ src/include/OSL/llvm_util.h | 2 + src/include/OSL/oslconfig.h.in | 24 +- src/include/OSL/oslexec.h | 17 +- src/include/OSL/rendererservices.h | 75 +-- src/include/OSL/rs_free_function.h | 359 +++++----- src/include/OSL/shaderglobals.h | 338 +++++++++- src/liboslcomp/typecheck.cpp | 1 + src/liboslexec/CMakeLists.txt | 2 +- src/liboslexec/backendllvm.cpp | 4 + src/liboslexec/backendllvm.h | 16 +- src/liboslexec/builtindecl.h | 18 +- src/liboslexec/constfold.cpp | 5 +- src/liboslexec/context.cpp | 36 +- src/liboslexec/dictionary.cpp | 61 +- src/liboslexec/journal.cpp | 624 +++++++++++------- src/liboslexec/llvm_gen.cpp | 424 +++++++----- src/liboslexec/llvm_instance.cpp | 106 ++- src/liboslexec/llvm_ops.cpp | 34 +- src/liboslexec/llvm_util.cpp | 12 +- src/liboslexec/opclosure.cpp | 12 + src/liboslexec/opcolor.cpp | 146 ++-- src/liboslexec/opcolor.h | 34 +- src/liboslexec/opfmt.cpp | 113 ++++ src/liboslexec/opmatrix.cpp | 96 ++- src/liboslexec/opmessage.cpp | 117 ++-- src/liboslexec/opnoise.cpp | 14 +- src/liboslexec/opstring.cpp | 92 +-- src/liboslexec/optexture.cpp | 10 +- src/liboslexec/oslexec_pvt.h | 46 +- src/liboslexec/rendservices.cpp | 156 ++--- src/liboslexec/rs_fallback.cpp | 150 ++--- src/liboslexec/runtimeoptimize.cpp | 4 + src/liboslexec/runtimeoptimize.h | 1 + src/liboslexec/shading_state_uniform.h | 22 +- src/liboslexec/shadingsys.cpp | 170 ++--- src/osltoy/osltoyrenderer.cpp | 21 - src/osltoy/osltoyrenderer.h | 6 - src/osltoy/render_state.h | 19 - src/testrender/render_state.h | 20 - src/testrender/simpleraytracer.cpp | 36 +- src/testrender/simpleraytracer.h | 13 +- src/testrender/testrender.cpp | 8 +- src/testshade/CMakeLists.txt | 6 - src/testshade/render_state.h | 6 +- src/testshade/rs_simplerend.cpp | 188 ++---- src/testshade/simplerend.cpp | 93 ++- src/testshade/simplerend.h | 44 +- src/testshade/testshade.cpp | 226 +++---- testsuite/example-deformer/osldeformer.cpp | 14 +- testsuite/test-fmt-arrays/ref/out.txt | 16 + testsuite/test-fmt-arrays/run.py | 7 + testsuite/test-fmt-arrays/test_arrays.osl | 33 + testsuite/test-fmt-cxpf/ref/out.txt | 180 +++++ testsuite/test-fmt-cxpf/run.py | 7 + testsuite/test-fmt-cxpf/test_cxpf.osl | 101 +++ .../test-fmt-errorwarning-repeats/ref/out.txt | 52 ++ .../test-fmt-errorwarning-repeats/run.py | 7 + .../test_errorwarning.osl | 22 + testsuite/test-fmt-errorwarning/ref/out.txt | 12 + testsuite/test-fmt-errorwarning/run.py | 7 + .../test_errorwarning.osl | 22 + testsuite/test-fmt-fileprint/ref/out.txt | 2 + .../test-fmt-fileprint/ref/out_fileprint.txt | 1 + testsuite/test-fmt-fileprint/run.py | 15 + .../test-fmt-fileprint/test_fileprint.osl | 13 + .../test-fmt-journalbuffercapacity/run.py | 7 + .../test_jbc.osl | 99 +++ testsuite/test-fmt-matrixcolor/ref/out.txt | 30 + testsuite/test-fmt-matrixcolor/run.py | 11 + .../test_2wrongspaces.osl | 23 + .../test_const_matrixcolor.osl | 38 ++ .../test-fmt-matrixcolor/test_matrixcolor.osl | 38 ++ testsuite/test-fmt-noise/ref/out.txt | 5 + testsuite/test-fmt-noise/run.py | 7 + testsuite/test-fmt-noise/test_noise.osl | 10 + testsuite/test-fmt-stpf/ref/out.txt | 28 + testsuite/test-fmt-stpf/run.py | 7 + testsuite/test-fmt-stpf/test_stpf.osl | 73 ++ 83 files changed, 3664 insertions(+), 1981 deletions(-) create mode 100644 src/include/OSL/fmt_util.h create mode 100644 src/include/OSL/journal.h create mode 100644 src/liboslexec/opfmt.cpp delete mode 100644 src/osltoy/render_state.h delete mode 100644 src/testrender/render_state.h create mode 100644 testsuite/test-fmt-arrays/ref/out.txt create mode 100644 testsuite/test-fmt-arrays/run.py create mode 100644 testsuite/test-fmt-arrays/test_arrays.osl create mode 100644 testsuite/test-fmt-cxpf/ref/out.txt create mode 100644 testsuite/test-fmt-cxpf/run.py create mode 100644 testsuite/test-fmt-cxpf/test_cxpf.osl create mode 100644 testsuite/test-fmt-errorwarning-repeats/ref/out.txt create mode 100644 testsuite/test-fmt-errorwarning-repeats/run.py create mode 100644 testsuite/test-fmt-errorwarning-repeats/test_errorwarning.osl create mode 100644 testsuite/test-fmt-errorwarning/ref/out.txt create mode 100644 testsuite/test-fmt-errorwarning/run.py create mode 100644 testsuite/test-fmt-errorwarning/test_errorwarning.osl create mode 100644 testsuite/test-fmt-fileprint/ref/out.txt create mode 100644 testsuite/test-fmt-fileprint/ref/out_fileprint.txt create mode 100644 testsuite/test-fmt-fileprint/run.py create mode 100644 testsuite/test-fmt-fileprint/test_fileprint.osl create mode 100644 testsuite/test-fmt-journalbuffercapacity/run.py create mode 100644 testsuite/test-fmt-journalbuffercapacity/test_jbc.osl create mode 100644 testsuite/test-fmt-matrixcolor/ref/out.txt create mode 100644 testsuite/test-fmt-matrixcolor/run.py create mode 100644 testsuite/test-fmt-matrixcolor/test_2wrongspaces.osl create mode 100644 testsuite/test-fmt-matrixcolor/test_const_matrixcolor.osl create mode 100644 testsuite/test-fmt-matrixcolor/test_matrixcolor.osl create mode 100644 testsuite/test-fmt-noise/ref/out.txt create mode 100644 testsuite/test-fmt-noise/run.py create mode 100644 testsuite/test-fmt-noise/test_noise.osl create mode 100644 testsuite/test-fmt-stpf/ref/out.txt create mode 100644 testsuite/test-fmt-stpf/run.py create mode 100644 testsuite/test-fmt-stpf/test_stpf.osl diff --git a/src/cmake/compiler.cmake b/src/cmake/compiler.cmake index c46b297d27..b02b2a5918 100644 --- a/src/cmake/compiler.cmake +++ b/src/cmake/compiler.cmake @@ -182,11 +182,6 @@ if (CMAKE_COMPILER_IS_GNUCC AND NOT (CMAKE_COMPILER_IS_CLANG OR CMAKE_COMPILER_I add_compile_options ("-Wno-error=strict-overflow") add_compile_options ("-Wno-unused-local-typedefs") add_compile_options ("-Wno-unused-result") - add_compile_options ("-Wno-attributes") - add_compile_options ("-Wno-error=sign-compare") - add_compile_options ("-Wno-error=class-memaccess") - add_compile_options ("-Wno-error=unused-variable") - add_compile_options ("-Wno-error=switch") if (NOT ${GCC_VERSION} VERSION_LESS 6.0) add_compile_options ("-Wno-error=misleading-indentation") endif () diff --git a/src/cmake/testing.cmake b/src/cmake/testing.cmake index ac55239289..8242ff6ff5 100644 --- a/src/cmake/testing.cmake +++ b/src/cmake/testing.cmake @@ -143,6 +143,17 @@ macro ( TESTSUITE ) add_one_testsuite ("${_testname}.opt" "${_testsrcdir}" ENV TESTSHADE_OPT=2 ) endif () + # Run the same test again with aggressive -O2 runtime + # optimization, triggered by setting TESTSHADE_OPT env variable. + # Skip OptiX-only tests and those with a NOOPTIMIZE marker file. + if (NOT _testname MATCHES "optix" + AND NOT EXISTS "${_testsrcdir}/NOSCALAR" + AND NOT EXISTS "${_testsrcdir}/BATCHED_REGRESSION" + AND NOT EXISTS "${_testsrcdir}/NOOPTIMIZE" + AND NOT EXISTS "${_testsrcdir}/NORSBITCODE") + add_one_testsuite ("${_testname}.opt.rs_bitcode" "${_testsrcdir}" + ENV TESTSHADE_OPT=2 TESTSHADE_RS_BITCODE=1) + endif () # When building for OptiX support, also run it in OptiX mode # if there is an OPTIX marker file in the directory. # If an environment variable $TESTSUITE_OPTIX is nonzero, then @@ -346,6 +357,9 @@ macro (osl_add_all_tests) struct-nested struct-nested-assign struct-nested-deep ternary testshade-expr + test-fmt-arrays test-fmt-fileprint + test-fmt-cxpf test-fmt-noise test-fmt-matrixcolor + test-fmt-stpf test-fmt-errorwarning test-fmt-errorwarning-repeats texture-alpha texture-alpha-derivs texture-blur texture-connected-options texture-derivs texture-environment texture-errormsg diff --git a/src/include/OSL/encodedtypes.h b/src/include/OSL/encodedtypes.h index 2925495438..f23377c3d7 100644 --- a/src/include/OSL/encodedtypes.h +++ b/src/include/OSL/encodedtypes.h @@ -6,61 +6,197 @@ #include +OSL_NAMESPACE_ENTER -enum class EncodedType : uint8_t -{ - kUstringHash, +// Substitute for variable argument list, which is traditionally used with a printf, with arrays +// of EncodedTypes to identify types contained in a blind payload of values. +enum class EncodedType : uint8_t { + // OSL Shaders could encode these types + kUstringHash = 0, kInt32, kFloat, - kDouble, // TODO: remove kDouble + + // OSL library functions or renderer services encode additional native types + kInt64, + kDouble, + kUInt32, + kUInt64, + kPointer, + kTypeDesc, + kCount }; + +// Decode will use each EncodedType in the array to interpret the contents of the arg_values +// parameter alongwith a fmtlib specifier identified by the ustring that the format_hash represents. +// Contents of decoded_str are written over (not appended). +// Returns # of bytes read from arg_values +int +decode_message(uint64_t format_hash, int32_t arg_count, + const EncodedType* arg_types, const uint8_t* arg_values, + std::string& decoded_str); + +namespace pvt { + +constexpr inline uint32_t +size_of_encoded_type(EncodedType et) +{ + constexpr uint32_t SizeByEncodedType[] = { + sizeof(OSL::ustringhash), sizeof(int32_t), sizeof(float), + sizeof(int64_t), sizeof(double), sizeof(uint32_t), + sizeof(uint64_t), sizeof(void*), sizeof(OSL::TypeDesc), + }; + static_assert(sizeof(SizeByEncodedType) / sizeof(SizeByEncodedType[0]) + == size_t(EncodedType::kCount), + "Keep array contents lined up with enum"); + return SizeByEncodedType[static_cast(et)]; +} + template -struct TypeEncoder; //Undefined on purpose; all types must have a specialization +struct TypeEncoder; //Undefined on purpose; all types must have a specialization +template<> struct TypeEncoder { + using DataType = ustringhash_pod; + static constexpr EncodedType value = EncodedType::kUstringHash; + static_assert(size_of_encoded_type(value) == sizeof(DataType), + "unexpected"); + static DataType Encode(const OSL::ustringhash& val) { return val.hash(); } +}; -namespace { - // MAYBE DONT NEED THIS -// ensure each compilation unit has its own lookup table by putting it in unnamed namespace -constexpr uint32_t SizeByEncodedType[] = { - sizeof(OSL::ustringhash), - sizeof(int32_t), - sizeof(float), - sizeof(double), - }; +template<> struct TypeEncoder { + using DataType = ustringhash_pod; + static constexpr EncodedType value = EncodedType::kUstringHash; + static_assert(size_of_encoded_type(value) == sizeof(DataType), + "unexpected"); + static DataType Encode(const OSL::ustring& val) { return val.hash(); } }; -template<> -struct TypeEncoder -{ - using DataType = OSL::ustringhash; - static constexpr EncodedType value = EncodedType::kUstringHash; +template<> struct TypeEncoder { + using DataType = ustringhash_pod; + static constexpr EncodedType value = EncodedType::kUstringHash; + static_assert(size_of_encoded_type(value) == sizeof(DataType), + "unexpected"); + static DataType Encode(const char* val) { return ustring(val).hash(); } }; -template<> -struct TypeEncoder -{ - using DataType = OSL::ustringhash; - static constexpr EncodedType value = EncodedType::kUstringHash; +template<> struct TypeEncoder { + using DataType = ustringhash_pod; + static constexpr EncodedType value = EncodedType::kUstringHash; + static_assert(size_of_encoded_type(value) == sizeof(DataType), + "unexpected"); + static DataType Encode(const std::string &val) { return ustring(val).hash(); } }; -template<> -struct TypeEncoder -{ - using DataType = int32_t; - static constexpr EncodedType value = EncodedType::kInt32; +template<> struct TypeEncoder { + using DataType = int32_t; + static constexpr EncodedType value = EncodedType::kInt32; + static_assert(size_of_encoded_type(value) == sizeof(DataType), + "unexpected"); + static DataType Encode(const int32_t val) { return val; } }; -template<> -struct TypeEncoder -{ - using DataType = float; - static constexpr EncodedType value = EncodedType::kFloat; +template<> struct TypeEncoder { + using DataType = float; + static constexpr EncodedType value = EncodedType::kFloat; + static_assert(size_of_encoded_type(value) == sizeof(DataType), + "unexpected"); + static DataType Encode(const float val) { return val; } }; -template<> -struct TypeEncoder -{ - using DataType = double; - static constexpr EncodedType value = EncodedType::kDouble; + +template<> struct TypeEncoder { + using DataType = int64_t; + static constexpr EncodedType value = EncodedType::kInt64; + static_assert(size_of_encoded_type(value) == sizeof(DataType), + "unexpected"); + static DataType Encode(const int64_t val) { return val; } +}; + +template<> struct TypeEncoder { + using DataType = double; + static constexpr EncodedType value = EncodedType::kDouble; + static_assert(size_of_encoded_type(value) == sizeof(DataType), + "unexpected"); + static DataType Encode(const double val) { return val; } +}; + +template<> struct TypeEncoder { + using DataType = uint64_t; + static constexpr EncodedType value = EncodedType::kUInt64; + static_assert(size_of_encoded_type(value) == sizeof(DataType), + "unexpected"); + static DataType Encode(const uint64_t val) { return val; } }; + +template<> struct TypeEncoder { + using DataType = uint32_t; + static constexpr EncodedType value = EncodedType::kUInt32; + static_assert(size_of_encoded_type(value) == sizeof(DataType), + "unexpected"); + static DataType Encode(const uint32_t val) { return val; } +}; + +template struct TypeEncoder { + // fmtlib only supports const void *, all other pointers must be + // converted with a cast or helper like fmt::ptr(p) + static_assert( + (std::is_same::value || std::is_same::value), + "formatting of non-void pointers is disallowed, wrap with fmt::ptr"); + + using DataType = const T*; + static constexpr EncodedType value = EncodedType::kPointer; + static_assert(size_of_encoded_type(value) == sizeof(DataType), + "unexpected"); + static DataType Encode(const T* val) { return val; } +}; + +template<> struct TypeEncoder { + // To avoid warnings about non-pod types when we PackArgs + // we will encode into builtin type + using DataType = uint64_t; + static_assert(sizeof(OSL::TypeDesc) == sizeof(DataType), "unexpected"); + static constexpr EncodedType value = EncodedType::kTypeDesc; + static_assert(size_of_encoded_type(value) == sizeof(DataType), + "unexpected"); + static DataType Encode(const OSL::TypeDesc& val) + { + return OSL::bitcast(val); + } +}; + +// Promote thinner types +template<> struct TypeEncoder { + using DataType = int32_t; + static constexpr EncodedType value = EncodedType::kInt32; + static_assert(size_of_encoded_type(value) == sizeof(DataType), + "unexpected"); + static DataType Encode(const int16_t val) { return DataType(val); } +}; + +template<> struct TypeEncoder { + using DataType = int32_t; + static constexpr EncodedType value = EncodedType::kInt32; + static_assert(size_of_encoded_type(value) == sizeof(DataType), + "unexpected"); + static DataType Encode(const int8_t val) { return DataType(val); } +}; + +template<> struct TypeEncoder { + using DataType = uint32_t; + static constexpr EncodedType value = EncodedType::kUInt32; + static_assert(size_of_encoded_type(value) == sizeof(DataType), + "unexpected"); + static DataType Encode(const uint16_t val) { return DataType(val); } +}; + +template<> struct TypeEncoder { + using DataType = uint32_t; + static constexpr EncodedType value = EncodedType::kUInt32; + static_assert(size_of_encoded_type(value) == sizeof(DataType), + "unexpected"); + static DataType Encode(const uint8_t val) { return DataType(val); } +}; +} // namespace pvt + + +OSL_NAMESPACE_EXIT \ No newline at end of file diff --git a/src/include/OSL/fmt_util.h b/src/include/OSL/fmt_util.h new file mode 100644 index 0000000000..5d05a434fa --- /dev/null +++ b/src/include/OSL/fmt_util.h @@ -0,0 +1,134 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +#pragma once + +#include + +// OSL library functions as well as Renderer Service free functions +// can utilize OSL::filefmt, OSL::printfmt, OSL::errorfmt, and +// OSL::warningfmt wrappers to accept variable arguments to be +// encoded into a EncodeType array and PackedArgument buffer +// that underlying render service free functions require. +// NOTE: All strings arguments to the underlying render service free +// functions must be ustringhash. To make this easier, these wrappers +// automatically convert ustring and const char * to ustringhash. + +OSL_NAMESPACE_ENTER + +namespace pvt { +// PackedArgs is similar to tuple but packs its data back to back +// in memory layout, which is what we need to build up payload +// to the fmt reporting system +template struct PackedArg { + explicit PackedArg(const TypeT& a_value) : m_value(a_value) {} + TypeT m_value; +} __attribute__((packed, aligned(1))); + +template struct PackedArgsBase; +// Specialize to extract a parameter pack of the IntegerSquence +// so it can be expanded alongside the TypeListT parameter pack +template +struct PackedArgsBase, TypeListT...> + : public PackedArg... { + explicit PackedArgsBase(const TypeListT&... a_values) + // multiple inheritance of individual components + // uniquely identified by the combo + : PackedArg(a_values)... + { + } +} __attribute__((packed, aligned(1))); + +template struct PackedArgs { + typedef std::make_integer_sequence + IndexSequenceType; + PackedArgsBase m_components; + + explicit PackedArgs(const TypeListT&... a_values) + : m_components(a_values...) + { + } +}; +} // namespace pvt + + + +template +void +filefmt(OpaqueExecContextPtr oec, const FilenameT& filename_hash, + const SpecifierT& fmt_specification, ArgListT... args) +{ + constexpr int32_t count = sizeof...(args); + constexpr OSL::EncodedType argTypes[] + = { pvt::TypeEncoder::value... }; + pvt::PackedArgs::DataType...> argValues { + pvt::TypeEncoder::Encode(args)... + }; + + rs_filefmt(oec, OSL::ustringhash { filename_hash }, + OSL::ustringhash { fmt_specification }, count, + (count == 0) ? nullptr : argTypes, + static_cast((count == 0) ? 0 : sizeof(argValues)), + (count == 0) ? nullptr : reinterpret_cast(&argValues)); +} + +template +void +printfmt(OpaqueExecContextPtr oec, const SpecifierT& fmt_specification, + ArgListT... args) +{ + constexpr int32_t count = sizeof...(args); + constexpr OSL::EncodedType argTypes[] + = { pvt::TypeEncoder::value... }; + pvt::PackedArgs::DataType...> argValues { + pvt::TypeEncoder::Encode(args)... + }; + + rs_printfmt(oec, OSL::ustringhash { fmt_specification }, count, + (count == 0) ? nullptr : argTypes, + static_cast((count == 0) ? 0 : sizeof(argValues)), + (count == 0) ? nullptr + : reinterpret_cast(&argValues)); +} + +template +void +errorfmt(OpaqueExecContextPtr oec, const SpecifierT& fmt_specification, + ArgListT... args) +{ + constexpr int32_t count = sizeof...(args); + constexpr OSL::EncodedType argTypes[] + = { pvt::TypeEncoder::value... }; + pvt::PackedArgs::DataType...> argValues { + pvt::TypeEncoder::Encode(args)... + }; + + rs_errorfmt(oec, OSL::ustringhash { fmt_specification }, count, + (count == 0) ? nullptr : argTypes, + static_cast((count == 0) ? 0 : sizeof(argValues)), + (count == 0) ? nullptr + : reinterpret_cast(&argValues)); +} + +template +void +warningfmt(OpaqueExecContextPtr oec, const SpecifierT& fmt_specification, + ArgListT... args) +{ + constexpr int32_t count = sizeof...(args); + constexpr OSL::EncodedType argTypes[] + = { pvt::TypeEncoder::value... }; + pvt::PackedArgs::DataType...> argValues { + pvt::TypeEncoder::Encode(args)... + }; + + rs_warningfmt(oec, OSL::ustringhash { fmt_specification }, count, + (count == 0) ? nullptr : argTypes, + static_cast((count == 0) ? 0 : sizeof(argValues)), + (count == 0) ? nullptr + : reinterpret_cast(&argValues)); +} + + +OSL_NAMESPACE_EXIT diff --git a/src/include/OSL/journal.h b/src/include/OSL/journal.h new file mode 100644 index 0000000000..7fa437b552 --- /dev/null +++ b/src/include/OSL/journal.h @@ -0,0 +1,364 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +#pragma once + +#include +#ifdef __CUDACC__ +# include +#endif + +#include +#include + + +OSL_NAMESPACE_ENTER + +/// Journal Buffer approach: each thread gets its own chain of pages within +/// the shared journal buffer for recording errors, warnings, etc. +/// By maintaining a separate chain per thread we can record errors (etc.) in a +/// non-blocking fashion. Shade index is recorded for use by error reporter to +/// sort messages but it is not used at present. +/// Using a Journal buffer is up to a Renderer. The Renderer use the new +/// customization points (rs_errorfmt, rs_filefmt, rs_printfmt, rs_warningfmt +/// or their virtual function equivalents) to interact with a journal::Writer +/// and journal buffer owned by its RenderState. The Renderer would of have to +/// allocate and initialized the journal buffer with the requested page size +/// and number of threads before executing a shader. After a shader is done +/// executing, the contents of the journal buffer can be transfered back to the +/// host and processed with a journal::Reader, which reports them through a +/// journal::Reporter's virtual interface. Intent is for Renderers's to use the +/// Journal buffer and provide their own overriden version of the +/// journal::Reporter. Testshade provides example usage. +/// For legacy purposes, the default virtual RendererServices will route errors +/// to ShadingSystem's OSL::ErrorHandler, but intent is for Renderer's to +/// switch over to using a Journal buffer or their own custom logging. + +namespace journal { + +namespace pvt { +//Per thread information for its page +struct alignas(64) PageInfo { + uint32_t pos; + uint32_t remaining; + uint32_t warning_count; +}; + +struct Organization //Initial bookkeeping +{ + int thread_count; + uint32_t buf_size; + uint32_t page_size; + +// rename free_pos bytes_used; +#ifdef __CUDACC__ + using AtomicUint32 = cuda::std::atomic; +#else + using AtomicUint32 = std::atomic; +#endif + alignas(64) + AtomicUint32 free_pos; // cache line alignment to avoid false sharing + alignas(64) AtomicUint32 + additional_bytes_required; // when the journal is full, how many more bytes would of been needed + alignas(64) AtomicUint32 + exceeded_page_size; // when the a single entry exceeds the page size, we can't record it, but we can track how space it needed + + uint32_t calc_end_of_page_infos() const + { + return sizeof(PageInfo) * thread_count + sizeof(Organization); + } + uint32_t calc_head_pos(int thread_index) const + { + return calc_end_of_page_infos() + (thread_index * page_size); + } + + PageInfo& get_pageinfo(int thread_index) + { + return reinterpret_cast( + reinterpret_cast(this) + + sizeof(Organization))[thread_index]; + } +}; + +enum class Content : uint8_t { + PageTransition, + // Shader Language generated + Error, + Warning, + Print, + FilePrint +}; + +static_assert(sizeof(PageInfo) % 64 == 0, "PageInfo needs to be cache aligned"); +} // namespace pvt + + +/// Call before launching shaders or after processing +/// returns: true for success, +/// false if buf_size can not accomadate at least 1 page per thread +OSLEXECPUBLIC bool +initialize_buffer(uint8_t* const buffer, uint32_t buf_size_, + uint32_t page_size_, int thread_count_); + +/// Abstract base class intended for Renders to override and handle messages +/// decoded from a journal buffer +class OSLEXECPUBLIC Reporter { + //Methods will NOT be called by multiple threads (no synchronization needed) +public: + virtual ~Reporter() {} + virtual void report_error(int thread_index, int shade_index, + const OSL::string_view& message) + = 0; + virtual void report_warning(int thread_index, int shade_index, + const OSL::string_view& message) + = 0; + virtual void report_print(int thread_index, int shade_index, + const OSL::string_view& message) + = 0; + virtual void report_file_print(int thread_index, int shade_index, + const OSL::string_view& filename, + const OSL::string_view& message) + = 0; +}; + +/// Utility class to look for repeated errors or warnings over +/// a limited history window +class OSLEXECPUBLIC TrackRecentlyReported { +public: + TrackRecentlyReported(bool limit_errors = true, + int error_history_capacity = 32, + bool limit_warnings = true, + int warning_history_capacity = 32); + + bool shouldReportError(const OSL::string_view& message); + bool shouldReportWarning(const OSL::string_view& message); + +protected: + const bool m_limit_errors; + const int m_error_history_capacity; + const bool m_limit_warnings; + const int m_warning_history_capacity; + std::list m_errseen, m_warnseen; +}; + +/// Concrete Reporter that utilizes a TrackRecentlyReported to filter and +/// forwards to a legacy OSL::ErrorHandler +class OSLEXECPUBLIC Report2ErrorHandler : public Reporter { +public: + Report2ErrorHandler(OSL::ErrorHandler* eh, TrackRecentlyReported& tracker); + void report_error(int thread_index, int shade_index, + const OSL::string_view& message) override; + void report_warning(int thread_index, int shade_index, + const OSL::string_view& message) override; + void report_print(int thread_index, int shade_index, + const OSL::string_view& message) override; + void report_file_print(int thread_index, int shade_index, + const OSL::string_view& filename, + const OSL::string_view& message) override; + +protected: + OSL::ErrorHandler* m_eh; + TrackRecentlyReported& m_tracker; +}; + +/// Reader is a lightweight class meant to be constructed as a local variable +/// with an already initalized (and populated) journal buffer and a concreate +/// Reporter. Calling process will decode all of the messages in the journal +/// calling the appropriate methods on the provided Reportor. +/// NOTE: Renderer is expected to call initialize_buffer after Reader::process +/// before reusing the buffer for additional shading. +class OSLEXECPUBLIC Reader { +public: + Reader(const uint8_t* buffer_, Reporter& reporter); + void process(); + +private: + void process_entries_for_thread(int thread_index); + + const uint8_t* const m_buffer; //Read from this? + const pvt::Organization& m_org; // + const pvt::PageInfo* m_pageinfo_by_thread_index; + Reporter& m_reporter; +}; + +/// Writer is a lightweight class meant to be constructed as a local variable +/// with an already initalized journal buffer and used to record error, +/// warnings, prints, or fprints into the buffer and then go out of scope. +/// Writer implementation entirely inlinable and intended for use on devices. +class OSLEXECPUBLIC Writer { +public: + Writer(void* buffer) + : m_buffer(static_cast(buffer)) + , m_org(*(reinterpret_cast(buffer))) + , m_pageinfo_by_thread_index(reinterpret_cast( + m_buffer + sizeof(pvt::Organization))) + { + } + + bool record_errorfmt(int thread_index, int shade_index, + OSL::ustringhash fmt_specification, int32_t arg_count, + const EncodedType* arg_types, uint32_t arg_values_size, + uint8_t* arg_values) + { + return write_entry(thread_index, shade_index, pvt::Content::Error, + fmt_specification, OSL::ustringhash {} /*filename*/, + arg_count, arg_types, arg_values_size, arg_values); + } + + bool record_warningfmt(int max_warnings_per_thread, int thread_index, + int shade_index, OSL::ustringhash fmt_specification, + int32_t arg_count, const EncodedType* arg_types, + uint32_t arg_values_size, uint8_t* arg_values) + { + auto& info = m_pageinfo_by_thread_index[thread_index]; + + if (static_cast(info.warning_count) >= max_warnings_per_thread) { + return false; + } + ++info.warning_count; + return write_entry(thread_index, shade_index, pvt::Content::Warning, + fmt_specification, OSL::ustringhash {} /*filename*/, + arg_count, arg_types, arg_values_size, arg_values); + } + + bool record_printfmt(int thread_index, int shade_index, + OSL::ustringhash fmt_specification, int32_t arg_count, + const EncodedType* arg_types, uint32_t arg_values_size, + uint8_t* arg_values) + { + return write_entry(thread_index, shade_index, pvt::Content::Print, + fmt_specification, OSL::ustringhash {} /*filename*/, + arg_count, arg_types, arg_values_size, arg_values); + } + + bool record_filefmt(int thread_index, int shade_index, + OSL::ustringhash filename_hash, + OSL::ustringhash fmt_specification, int32_t arg_count, + const EncodedType* arg_types, uint32_t arg_values_size, + uint8_t* arg_values) + { + return write_entry(thread_index, shade_index, pvt::Content::FilePrint, + fmt_specification, filename_hash, arg_count, + arg_types, arg_values_size, arg_values); + } + +private: + static constexpr size_t requiredForPageTransition() + { + return sizeof(pvt::Content::PageTransition) + sizeof(uint32_t); + } + bool allocatePage(int thread_index) + { + using pvt::Content; + auto& info = m_pageinfo_by_thread_index[thread_index]; + + OSL_ASSERT(info.remaining >= requiredForPageTransition()); + + // pre check if next_pos >= buf_size to prevent continuing to + // increment free_pos once its already past the end of a page + if ((m_org.free_pos.load() + m_org.page_size) >= m_org.buf_size) + return false; + + uint32_t next_pos = m_org.free_pos.fetch_add(m_org.page_size); + // post check if next_pos >= buf_size because another thread could + // have bumped free_pos + if (next_pos >= m_org.buf_size) + return false; + + // write page transition + uint8_t* dest_ptr = m_buffer + info.pos; + constexpr Content content = Content::PageTransition; + memcpy(dest_ptr, &content, sizeof(content)); + memcpy(dest_ptr + sizeof(content), &next_pos, sizeof(next_pos)); + // Don't bother update page info for the memory used by the transition + // because we are about to overwrite it. + + // Update page info to point to newly allocated page + info.pos = next_pos; + info.remaining = m_org.page_size; + info.warning_count = 0; + return true; + } + + bool write_entry(int thread_index, int shade_index, pvt::Content content, + OSL::ustringhash fmt_specification, + OSL::ustringhash filename, int32_t arg_count, + const EncodedType* arg_types, uint32_t arg_values_size, + uint8_t* arg_values) + { + using pvt::Content; + + uint64_t fname_hash; + // calc required size for this entry + uint64_t fmt_spec_hash = fmt_specification.hash(); + uint32_t required_bytes = sizeof(Content) + sizeof(int) + + sizeof(fmt_spec_hash) + sizeof(arg_count) + + sizeof(EncodedType) * arg_count + + arg_values_size; + + if (filename.hash()) { + fname_hash = filename.hash(); + required_bytes += sizeof(fname_hash); + } + + + if (required_bytes > m_org.page_size) { + uint32_t exceeded = m_org.exceeded_page_size; + while (required_bytes > exceeded) { + if (m_org.exceeded_page_size.compare_exchange_weak( + exceeded, required_bytes)) { + break; + } + } + return false; + } + + auto& info = m_pageinfo_by_thread_index[thread_index]; + + if ((info.remaining - requiredForPageTransition()) < required_bytes) { + // TODO (extra credit): get fancy spanning entry over multiple pages + if (!allocatePage(thread_index)) { + m_org.additional_bytes_required += required_bytes; + return false; + } + } + + OSL_ASSERT(info.remaining >= required_bytes); + uint8_t* dest_ptr = m_buffer + info.pos; + + memcpy(dest_ptr, &content, sizeof(content)); + memcpy(dest_ptr + sizeof(content), &shade_index, sizeof(shade_index)); + memcpy(dest_ptr + sizeof(content) + sizeof(shade_index), &fmt_spec_hash, + sizeof(fmt_spec_hash)); + memcpy(dest_ptr + sizeof(content) + sizeof(shade_index) + + sizeof(fmt_spec_hash), + &arg_count, sizeof(arg_count)); + memcpy(dest_ptr + sizeof(content) + sizeof(shade_index) + + sizeof(fmt_spec_hash) + sizeof(arg_count), + arg_types, sizeof(EncodedType) * arg_count); + memcpy(dest_ptr + sizeof(content) + sizeof(shade_index) + + sizeof(fmt_spec_hash) + sizeof(arg_count) + + sizeof(EncodedType) * arg_count, + arg_values, arg_values_size); + if (content == Content::FilePrint) { + uint64_t filename_hash = filename.hash(); + memcpy(dest_ptr + sizeof(content) + sizeof(shade_index) + + sizeof(fmt_spec_hash) + sizeof(arg_count) + + sizeof(EncodedType) * arg_count + arg_values_size, + &filename_hash, sizeof(filename_hash)); + } + + info.remaining -= required_bytes; + info.pos += required_bytes; + return true; + } + + uint8_t* m_buffer; + pvt::Organization& m_org; + pvt::PageInfo* m_pageinfo_by_thread_index; +}; + +} // namespace journal + +OSL_NAMESPACE_EXIT \ No newline at end of file diff --git a/src/include/OSL/llvm_util.h b/src/include/OSL/llvm_util.h index df842b4cbf..b42eee776f 100644 --- a/src/include/OSL/llvm_util.h +++ b/src/include/OSL/llvm_util.h @@ -546,6 +546,7 @@ class OSLEXECPUBLIC LLVM_Util { llvm::PointerType* type_bool_ptr() const { return m_llvm_type_bool_ptr; } llvm::PointerType* type_int_ptr() const { return m_llvm_type_int_ptr; } llvm::PointerType* type_int8_ptr() const { return m_llvm_type_int8_ptr; } + llvm::PointerType* type_int64_ptr() const { return m_llvm_type_int64_ptr; } llvm::PointerType* type_float_ptr() const { return m_llvm_type_float_ptr; } llvm::PointerType* type_longlong_ptr() const { @@ -1063,6 +1064,7 @@ class OSLEXECPUBLIC LLVM_Util { llvm::PointerType* m_llvm_type_bool_ptr; llvm::PointerType* m_llvm_type_int_ptr; llvm::PointerType* m_llvm_type_int8_ptr; + llvm::PointerType* m_llvm_type_int64_ptr; llvm::PointerType* m_llvm_type_float_ptr; llvm::PointerType* m_llvm_type_longlong_ptr; llvm::PointerType* m_llvm_type_triple_ptr; diff --git a/src/include/OSL/oslconfig.h.in b/src/include/OSL/oslconfig.h.in index 8d800a5a23..6f612b6841 100644 --- a/src/include/OSL/oslconfig.h.in +++ b/src/include/OSL/oslconfig.h.in @@ -124,6 +124,7 @@ using OIIO::TypeInt; using OIIO::TypeFloat2; using OIIO::TypeVector2; using OIIO::TypeVector4; +using OIIO::TypeUInt64; using OIIO::Strutil::print; @@ -150,7 +151,6 @@ fmtformat_to_n(OutIt &out, size_t n, const string_view& fmt, Args&&... args) } - /// OSL_USTRINGREP_IS_HASH will be 1 if the build-time option was enabled to /// make the ustringrep be a ustringhash, rather than a ustring directly. #cmakedefine01 OSL_USTRINGREP_IS_HASH @@ -209,22 +209,24 @@ ustringhash_from(ustringhash u) inline ustringhash ustringhash_from(ustringhash_pod u) { - return *reinterpret_cast(&u); +#if OIIO_VERSION_GREATER_EQUAL(2, 4, 10) + return ustringhash{u}; +#else + // No constructor taking the pod type existed previously + // so bitcast it. + return OSL::bitcast(u); +#endif } -// /// Convenience function to convert ustringhash to a USTRINGHASH_PO. -// inline ustringhash -// ustringpod_from(ustringhash u) -// { -// return *reinterpret_cast(&u); -// } - - /// Convenience function to convert to a ustringhash. inline ustringhash ustringhash_from(ustring u) { - return u.uhash(); + ustringhash ret; + // Not legal to call uhash on an empty ustring + if(!u.empty()) + ret = u.uhash(); + return ret; } diff --git a/src/include/OSL/oslexec.h b/src/include/OSL/oslexec.h index 1c1e721e9b..f3884aea19 100644 --- a/src/include/OSL/oslexec.h +++ b/src/include/OSL/oslexec.h @@ -10,7 +10,6 @@ #include #include -#include OSL_NAMESPACE_ENTER @@ -789,9 +788,10 @@ class OSLEXECPUBLIC ShadingSystem { /// execute_layer of the last (presumably group entry) layer, and /// execute_cleanup. If run==false, just do the binding and setup, don't /// actually run the shader. - bool execute(ShadingContext& ctx, ShaderGroup& group, int thread_index, int shadeindex, - ShaderGlobals& globals, void* userdata_base_ptr, - void* output_base_ptr, bool run = true); + bool execute(ShadingContext& ctx, ShaderGroup& group, int thread_index, + int shadeindex, ShaderGlobals& globals, + void* userdata_base_ptr, void* output_base_ptr, + bool run = true); /// Future execute signature that will be range based. Shader globals will be /// obtained from renderer services. @@ -824,9 +824,10 @@ class OSLEXECPUBLIC ShadingSystem { /// preparation, but don't actually run the shader. Return true if the /// shader executed, false if it did not (including if the shader itself /// was empty). - bool execute_init(ShadingContext& ctx, ShaderGroup& group, int threadindex, int shadeindex, - ShaderGlobals& globals, void* userdata_base_ptr, - void* output_base_ptr, bool run = true); + bool execute_init(ShadingContext& ctx, ShaderGroup& group, int threadindex, + int shadeindex, ShaderGlobals& globals, + void* userdata_base_ptr, void* output_base_ptr, + bool run = true); // DEPRECATED(2.0): no shadeindex or base pointers bool execute_init(ShadingContext& ctx, ShaderGroup& group, ShaderGlobals& globals, bool run = true) @@ -839,7 +840,7 @@ class OSLEXECPUBLIC ShadingSystem { /// run==true, and that the call to execute_init() returned true. (One /// reason why it might have returned false is if the shader group /// turned out, after optimization, to do nothing.) - bool execute_layer(ShadingContext& ctx, int threadindex, int shadeindex, + bool execute_layer(ShadingContext& ctx, int threadindex, int shadeindex, ShaderGlobals& globals, void* userdata_base_ptr, void* output_base_ptr, int layernumber); /// Execute the layer by name. diff --git a/src/include/OSL/rendererservices.h b/src/include/OSL/rendererservices.h index 3e612b5ff5..039d081fec 100644 --- a/src/include/OSL/rendererservices.h +++ b/src/include/OSL/rendererservices.h @@ -5,8 +5,8 @@ #pragma once -#include #include +#include OSL_NAMESPACE_ENTER @@ -157,34 +157,37 @@ class OSLEXECPUBLIC RendererServices { Vec3* Pout, int npoints, TypeDesc::VECSEMANTICS vectype); - virtual void errorfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); - - virtual void warningfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); - - virtual void printfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); - - virtual void filefmt(OSL::ShaderGlobals* sg, - OSL::ustringhash filename_hash, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); + /// Report errors, warnings, printf, and fprintf. + /// Fmtlib style format specifier is used (vs. printf style) + /// Arguments are represented as EncodedTypes (encodedtypes.h) and + /// packed into an arg_values buffer. OSL::decode_message converts these + /// arguments into a std::string for renderer's handle to use as they please. + /// For device compatibility, the format specifier and any string arguments + /// are passed as ustringhash's. + /// Default implementation decodes the messages and fowards them to the + /// ShadingContext onto the ShadyingSystem's ErrorHandler. + /// It is recomended to override and make use of the + /// journal buffer to record everything to a buffer than can be post + /// processed as needed vs. going through the ShadingSystem ErrorHandler. + virtual void errorfmt(OSL::ShaderGlobals* sg, + OSL::ustringhash fmt_specification, int32_t arg_count, + const EncodedType* arg_types, + uint32_t arg_values_size, uint8_t* arg_values); + + virtual void warningfmt(OSL::ShaderGlobals* sg, + OSL::ustringhash fmt_specification, + int32_t arg_count, const EncodedType* arg_types, + uint32_t arg_values_size, uint8_t* arg_values); + + virtual void printfmt(OSL::ShaderGlobals* sg, + OSL::ustringhash fmt_specification, int32_t arg_count, + const EncodedType* arg_types, + uint32_t arg_values_size, uint8_t* arg_values); + + virtual void filefmt(OSL::ShaderGlobals* sg, OSL::ustringhash filename_hash, + OSL::ustringhash fmt_specification, int32_t arg_count, + const EncodedType* arg_types, uint32_t arg_values_size, + uint8_t* arg_values); /// Get the named attribute from the renderer and if found then @@ -352,17 +355,15 @@ class OSLEXECPUBLIC RendererServices { virtual bool get_texture_info(ustringhash filename, TextureHandle* texture_handle, TexturePerthread* texture_thread_info, - ShadingContext* shading_context, int subimage, + ShaderGlobals* sg, int subimage, ustringhash dataname, TypeDesc datatype, void* data, ustringhash* errormessage); - virtual bool get_texture_info(ustringhash filename, - TextureHandle* texture_handle, float s, - float t, - TexturePerthread* texture_thread_info, - ShadingContext* shading_context, int subimage, - ustringhash dataname, TypeDesc datatype, - void* data, ustringhash* errormessage); + virtual bool + get_texture_info(ustringhash filename, TextureHandle* texture_handle, + float s, float t, TexturePerthread* texture_thread_info, + ShaderGlobals* sg, int subimage, ustringhash dataname, + TypeDesc datatype, void* data, ustringhash* errormessage); /// Lookup nearest points in a point cloud. It will search for diff --git a/src/include/OSL/rs_free_function.h b/src/include/OSL/rs_free_function.h index f3026eff9f..a0b5f17445 100644 --- a/src/include/OSL/rs_free_function.h +++ b/src/include/OSL/rs_free_function.h @@ -2,8 +2,10 @@ // SPDX-License-Identifier: BSD-3-Clause // https://github.com/AcademySoftwareFoundation/OpenShadingLanguage -#include +#pragma once + #include +#include // Make all the strings defined in OSL // available to the renderer services free functions @@ -31,33 +33,17 @@ extern "C" { // "C" linkage (no C++ name mangling) and local visibility #define OSL_RSOP extern "C" -/// Type for an opaque pointer to whatever the Shading System uses to represent -/// Execution Context. -typedef void* OpaqueExecContextPtr; - -template -RenderStateT* osl_get_rs(OpaqueExecContextPtr cptr) { -auto sg = reinterpret_cast(cptr); -auto rs = reinterpret_cast(sg->renderstate); -return rs; -} - -template -ShaderGlobalsT* osl_get_sg(OpaqueExecContextPtr cptr) { -auto sg = reinterpret_cast(cptr); -return sg; -} - // We are choosing to use unique names encoding parameters directly // as opposed to using overloaded functions. // Keep free functions in sync with virtual function based RendererServices. +// Must be re-enterant; Expect to be called from multiple threads /// Get the 4x4 matrix that transforms by the specified /// transformation at the given time. Return true if ok, false /// on error. OSL_RSOP bool -rs_get_matrix_xform_time(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, +rs_get_matrix_xform_time(OSL::OpaqueExecContextPtr oec, OSL::Matrix44& result, OSL::TransformationPtr from, float time); /// Get the 4x4 matrix that transforms by the specified @@ -65,14 +51,15 @@ rs_get_matrix_xform_time(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx /// error. Suggested implementation is to use rs_get_matrix_xform_time and /// invert it, but a particular renderer may have a better technique. OSL_RSOP bool -rs_get_inverse_matrix_xform_time(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, +rs_get_inverse_matrix_xform_time(OSL::OpaqueExecContextPtr oec, + OSL::Matrix44& result, OSL::TransformationPtr xform, float time); /// Get the 4x4 matrix that transforms points from the named /// 'from' coordinate system to "common" space at the given time. /// Returns true if ok, false if the named matrix is not known. OSL_RSOP bool -rs_get_matrix_space_time(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, +rs_get_matrix_space_time(OSL::OpaqueExecContextPtr oec, OSL::Matrix44& result, OSL::StringParam from, float time); /// Get the 4x4 matrix that transforms points from "common" space to @@ -80,15 +67,16 @@ rs_get_matrix_space_time(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ct /// implementation is to use rs_get_matrix_space_time and invert it, but a /// particular renderer may have a better technique. OSL_RSOP bool -rs_get_inverse_matrix_space_time(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, - OSL::StringParam to, float time); +rs_get_inverse_matrix_space_time(OSL::OpaqueExecContextPtr oec, + OSL::Matrix44& result, OSL::StringParam to, + float time); /// Get the 4x4 matrix that transforms by the specified /// transformation. Return true if ok, false on error. Since no /// time value is given, also return false if the transformation may /// be time-varying. OSL_RSOP bool -rs_get_matrix_xform(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, +rs_get_matrix_xform(OSL::OpaqueExecContextPtr oec, OSL::Matrix44& result, OSL::TransformationPtr xform); /// Get the 4x4 matrix that transforms by the specified @@ -98,7 +86,8 @@ rs_get_matrix_xform(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, OS /// rs_get_matrix_xform and invert it, but a particular renderer may have a /// better technique. OSL_RSOP bool -rs_get_inverse_matrix_xform(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, +rs_get_inverse_matrix_xform(OSL::OpaqueExecContextPtr oec, + OSL::Matrix44& result, OSL::TransformationPtr xform); /// Get the 4x4 matrix that transforms 'from' to "common" space. @@ -106,7 +95,7 @@ rs_get_inverse_matrix_xform(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec /// transformation may be time-varying (as well as if it's not found /// at all). OSL_RSOP bool -rs_get_matrix_space(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, +rs_get_matrix_space(OSL::OpaqueExecContextPtr oec, OSL::Matrix44& result, OSL::StringParam from); /// Get the 4x4 matrix that transforms points from "common" space to @@ -116,8 +105,8 @@ rs_get_matrix_space(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, OS /// implementation is to use rs_get_matrix_space and invert it, but a /// particular renderer may have a better technique. OSL_RSOP bool -rs_get_inverse_matrix_space(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, - OSL::StringParam to); +rs_get_inverse_matrix_space(OSL::OpaqueExecContextPtr oec, + OSL::Matrix44& result, OSL::StringParam to); /// Transform points Pin[0..npoints-1] in named coordinate system /// 'from' into 'to' coordinates, storing the result in Pout[] using @@ -140,210 +129,162 @@ rs_get_inverse_matrix_space(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec /// if there isn't a special nonlinear transformation between the /// two spaces. OSL_RSOP bool -rs_transform_points(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, OSL::StringParam from, +rs_transform_points(OSL::OpaqueExecContextPtr oec, OSL::StringParam from, OSL::StringParam to, float time, const OSL::Vec3* Pin, OSL::Vec3* Pout, int npoints, OSL::TypeDesc::VECSEMANTICS vectype); +/// Report errors, warnings, printf, and fprintf. +/// Fmtlib style format specifier is used (vs. printf style) +/// Arguments are represented as EncodedTypes (encodedtypes.h) and +/// packed into an arg_values buffer. OSL::decode_message converts these +/// arguments into a std::string for renderer's handle to use as they please. +/// For device compatibility, the format specifier and any string arguments +/// are passed as ustringhash's. +/// It is recomended to override and make use of the journal buffer to record +/// everything to a buffer than can be post processed as needed. +OSL_RSOP void +rs_errorfmt(OSL::OpaqueExecContextPtr oec, OSL::ustringhash fmt_specification, + int32_t count, const OSL::EncodedType* argTypes, + uint32_t argValuesSize, uint8_t* argValues); -OSL_RSOP void rs_errorfmt_dummy(OpaqueExecContextPtr exec_ctx); - - -#if 0 -//Must be re-enterant; Expect to be called from multiple threads -OSL_RSOP void rs_errorfmt(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, - /*OSL::ustringhash*/ OSL::ustringhash_pod fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); - -template -void osl_errorfmt(OSL::ShaderGlobals* sg/*OpaqueExecContextPtr exec_ctx*/, - OSL::ustringhash fmt_specification, - ArgListT... args) -{ - constexpr int32_t count = sizeof...(args); - constexpr EncodedType argTypes[] = { TypeEncoder::value...}; - std::tuple::DataType...> __attribute__((packed,aligned(1))) argValues{ typename TypeEncoder::DataType{args}... }; - - //OSL::ustringrep rs_fmt_spec_ustring = OSL::ustringrep_from (fmt_specification); /*hash to ustring*/ - OSL::ustringhash_pod rs_fmt_spec = reinterpret_cast(&fmt_specification); - - rs_errorfmt_dummy(sg); - - //Need to get context - //auto rs = osl_get_rs(exec_ctx); - - auto sg_void = reinterpret_cast (sg); - +OSL_RSOP void +rs_filefmt(OSL::OpaqueExecContextPtr oec, OSL::ustringhash filname_hash, + OSL::ustringhash fmt_specification, int32_t count, + const OSL::EncodedType* argTypes, uint32_t argValuesSize, + uint8_t* argValues); - rs_errorfmt(sg_void, rs_fmt_spec, count, argTypes, static_cast(sizeof(argValues)), reinterpret_cast(&argValues)); -} +OSL_RSOP void +rs_printfmt(OSL::OpaqueExecContextPtr oec, OSL::ustringhash fmt_specification, + int32_t count, const OSL::EncodedType* argTypes, + uint32_t argValuesSize, uint8_t* argValues); -#endif -//Must be re-enterant; Expect to be called from multiple threads -OSL_RSOP void rs_errorfmt(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); - -template -void osl_errorfmt(OSL::ShaderGlobals* sg/*OpaqueExecContextPtr exec_ctx*/, - OSL::ustringhash fmt_specification, - ArgListT... args) -{ - constexpr int32_t count = sizeof...(args); - constexpr EncodedType argTypes[] = { TypeEncoder::value...}; - std::tuple::DataType...> __attribute__((packed,aligned(1))) argValues{ typename TypeEncoder::DataType{args}... }; +OSL_RSOP void +rs_warningfmt(OSL::OpaqueExecContextPtr oec, OSL::ustringhash fmt_specification, + int32_t count, const OSL::EncodedType* argTypes, + uint32_t argValuesSize, uint8_t* argValues); - auto sg_void = reinterpret_cast (sg); - - - rs_errorfmt(sg_void, fmt_specification/*a ustringhash*/, count, argTypes, static_cast(sizeof(argValues)), reinterpret_cast(&argValues)); -} #if 0 -OSL_RSOP void rs_filefmt(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, - /*OSL::ustringhash filname_hash*/ OSL::ustringhash_pod filename_hash, - /*OSL::ustringhash fmt_specification*/ OSL::ustringhash_pod fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); - -template -void osl_filefmt(OSL::ShaderGlobals* sg, - OSL::ustringhash filename_hash, - OSL::ustringhash fmt_specification, - ArgListT... args) -{ - constexpr int32_t count = sizeof...(args); - constexpr EncodedType argTypes[] = { TypeEncoder::value...}; - std::tuple::DataType...> __attribute__((packed,aligned(1))) argValues{ typename TypeEncoder::DataType{args}... }; - OSL::ustringhash_pod rs_filename_pod = reinterpret_cast(&filename_hash); - OSL::ustringhash_pod rs_fmt_spec = reinterpret_cast(&fmt_specification); - - //OSL::ustring_pod rs_fmt_spec = ustringpod_from(&fmt_specification); - - rs_filefmt(sg, rs_filename_pod, rs_fmt_spec, count, argTypes, static_cast(sizeof(argValues)), reinterpret_cast(&argValues)); -} -#endif - - -OSL_RSOP void rs_filefmt(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, - OSL::ustringhash filname_hash, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); +// C++ helpers to accept variable arguements and encode messages to be sent +// through renderer service free functions +OSL_NAMESPACE_ENTER -template -void osl_filefmt(OSL::ShaderGlobals* sg, - OSL::ustringhash filename_hash, - OSL::ustringhash fmt_specification, - ArgListT... args) +namespace pvt { +// PackedArgs is similar to tuple but packs its data back to back +// in memory layout, which is what we need to build up payload +// to the fmt reporting system +template struct PackedArg { + explicit PackedArg(const TypeT& a_value) : m_value(a_value) {} + TypeT m_value; +} __attribute__((packed, aligned(1))); + +template struct PackedArgsBase; +// Specialize to extract a parameter pack of the IntegerSquence +// so it can be expanded alongside the TypeListT parameter pack +template +struct PackedArgsBase, TypeListT...> + : public PackedArg... { + explicit PackedArgsBase(const TypeListT&... a_values) + // multiple inheritance of individual components + // uniquely identified by the combo + : PackedArg(a_values)... + { + } +} __attribute__((packed, aligned(1))); + +template struct PackedArgs { + typedef std::make_integer_sequence + IndexSequenceType; + PackedArgsBase m_components; + + explicit PackedArgs(const TypeListT&... a_values) + : m_components(a_values...) + { + } +}; +} // namespace pvt + + + +template +void +filefmt(OpaqueExecContextPtr oec, const FilenameT& filename_hash, + const SpecifierT& fmt_specification, ArgListT... args) { - constexpr int32_t count = sizeof...(args); - constexpr EncodedType argTypes[] = { TypeEncoder::value...}; - std::tuple::DataType...> __attribute__((packed,aligned(1))) argValues{ typename TypeEncoder::DataType{args}... }; - - - //OSL::ustring_pod rs_fmt_spec = ustringpod_from(&fmt_specification); - - rs_filefmt(sg, filename_hash,fmt_specification, count, argTypes, static_cast(sizeof(argValues)), reinterpret_cast(&argValues)); + constexpr int32_t count = sizeof...(args); + constexpr OSL::EncodedType argTypes[] + = { pvt::TypeEncoder::value... }; + pvt::PackedArgs::DataType...> argValues { + pvt::TypeEncoder::Encode(args)... + }; + + rs_filefmt(oec, OSL::ustringhash { filename_hash }, + OSL::ustringhash { fmt_specification }, count, + (count == 0) ? nullptr : argTypes, + static_cast((count == 0) ? 0 : sizeof(argValues)), + (count == 0) ? nullptr : reinterpret_cast(&argValues)); } -#if 0 -OSL_RSOP void rs_printfmt(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, - /*OSL::ustringhash fmt_specification*/ OSL::ustringhash_pod fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); - -template -void osl_printfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - ArgListT... args) +template +void +printfmt(OpaqueExecContextPtr oec, const SpecifierT& fmt_specification, + ArgListT... args) { - constexpr int32_t count = sizeof...(args); - constexpr EncodedType argTypes[] = { TypeEncoder::value...}; - std::tuple::DataType...> __attribute__((packed,aligned(1))) argValues{ typename TypeEncoder::DataType{args}... }; - OSL::ustringhash_pod rs_fmt_spec = reinterpret_cast(&fmt_specification); - //OSL::ustring_pod rs_fmt_spec = ustringpod_from(&fmt_specification); - - rs_printfmt(sg, rs_fmt_spec, count, argTypes, static_cast(sizeof(argValues)), reinterpret_cast(&argValues)); + constexpr int32_t count = sizeof...(args); + constexpr OSL::EncodedType argTypes[] + = { pvt::TypeEncoder::value... }; + pvt::PackedArgs::DataType...> argValues { + pvt::TypeEncoder::Encode(args)... + }; + + rs_printfmt(oec, OSL::ustringhash { fmt_specification }, count, + (count == 0) ? nullptr : argTypes, + static_cast((count == 0) ? 0 : sizeof(argValues)), + (count == 0) ? nullptr + : reinterpret_cast(&argValues)); } -#endif -OSL_RSOP void rs_printfmt(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); - -template -void osl_printfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - ArgListT... args) +template +void +errorfmt(OpaqueExecContextPtr oec, const SpecifierT& fmt_specification, + ArgListT... args) { - constexpr int32_t count = sizeof...(args); - constexpr EncodedType argTypes[] = { TypeEncoder::value...}; - std::tuple::DataType...> __attribute__((packed,aligned(1))) argValues{ typename TypeEncoder::DataType{args}... }; - - - - rs_printfmt(sg, fmt_specification, count, argTypes, static_cast(sizeof(argValues)), reinterpret_cast(&argValues)); + constexpr int32_t count = sizeof...(args); + constexpr OSL::EncodedType argTypes[] + = { pvt::TypeEncoder::value... }; + pvt::PackedArgs::DataType...> argValues { + pvt::TypeEncoder::Encode(args)... + }; + + rs_errorfmt(oec, OSL::ustringhash { fmt_specification }, count, + (count == 0) ? nullptr : argTypes, + static_cast((count == 0) ? 0 : sizeof(argValues)), + (count == 0) ? nullptr + : reinterpret_cast(&argValues)); } -#if 0 - -OSL_RSOP void rs_warningfmt(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, - /*OSL::ustringhash fmt_specification, */ OSL::ustringhash_pod fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); - -template -void osl_warningfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - ArgListT... args) +template +void +warningfmt(OpaqueExecContextPtr oec, const SpecifierT& fmt_specification, + ArgListT... args) { - constexpr int32_t count = sizeof...(args); - constexpr EncodedType argTypes[] = { TypeEncoder::value...}; - std::tuple::DataType...> __attribute__((packed,aligned(1))) argValues{ typename TypeEncoder::DataType{args}... }; - OSL::ustringhash_pod rs_fmt_spec = reinterpret_cast(&fmt_specification); - auto sg_void = reinterpret_cast (sg); - //We are losing SG info here - rs_warningfmt(sg_void, rs_fmt_spec, count, argTypes, static_cast(sizeof(argValues)), reinterpret_cast(&argValues)); + constexpr int32_t count = sizeof...(args); + constexpr OSL::EncodedType argTypes[] + = { pvt::TypeEncoder::value... }; + pvt::PackedArgs::DataType...> argValues { + pvt::TypeEncoder::Encode(args)... + }; + + rs_warningfmt(oec, OSL::ustringhash { fmt_specification }, count, + (count == 0) ? nullptr : argTypes, + static_cast((count == 0) ? 0 : sizeof(argValues)), + (count == 0) ? nullptr + : reinterpret_cast(&argValues)); } -#endif -OSL_RSOP void rs_warningfmt(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); - -template -void osl_warningfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - ArgListT... args) -{ - constexpr int32_t count = sizeof...(args); - constexpr EncodedType argTypes[] = { TypeEncoder::value...}; - std::tuple::DataType...> __attribute__((packed,aligned(1))) argValues{ typename TypeEncoder::DataType{args}... }; - - auto sg_void = reinterpret_cast (sg); - rs_warningfmt(sg_void, fmt_specification, count, argTypes, static_cast(sizeof(argValues)), reinterpret_cast(&argValues)); -} +OSL_NAMESPACE_EXIT +#endif \ No newline at end of file diff --git a/src/include/OSL/shaderglobals.h b/src/include/OSL/shaderglobals.h index 8bb9b65fb3..cc6c22d2c2 100644 --- a/src/include/OSL/shaderglobals.h +++ b/src/include/OSL/shaderglobals.h @@ -36,6 +36,22 @@ typedef const void* OpaqueShadingStateUniformPtr; /// /// All points, vectors and normals are given in "common" space. /// + +/// We are working towards making ShaderGlobals a private implementation +/// detail. Preference is given to utilizing an Opaque Execution Context +/// Pointer with accessor functions (setter/getters) to access shader global +/// values or any context for the currently executing shade. These accessors +/// are at the bottom of this file following the form: +/// const Vec3& get_P(const OpaqueExecContextPtr oec); +/// const Vec3& get_N(const OpaqueExecContextPtr oec); +/// float get_time(const OpaqueExecContextPtr oec); +/// int get_shade_index(const OpaqueExecContextPtr oec); +/// Currently ExecutionContext is a ShaderGlobals and can be used +/// interchangably. After inlining we don't expect worse performance. +/// Users should transition to the new accessor function API. Once transition +/// is complete, where the values are stored and how they are populated is +/// expected to change and the new API will provide a layer of encapsulation +/// that the raw ShaderGlobals struct doesn't allow. struct ShaderGlobals { /// Surface position (and its x & y differentials). Vec3 P, dPdx, dPdy; @@ -88,12 +104,13 @@ struct ShaderGlobals { ShadingContext* context; OpaqueShadingStateUniformPtr shadingStateUniform; - ///Required by free function renderer services to process fmt specification calls - int shade_index; - - ///Required for memory allocation on a per thread basis for journaling fmt specification calls + /// Shading System responsible for setting + /// 0 based thread index, required by journaling mechanism int thread_index; + /// Shading System responsible for setting + int shade_index; + /// Pointer to the RendererServices object. This is how OSL finds its /// way back to the renderer for callbacks. RendererServices* renderer; @@ -150,4 +167,317 @@ enum class SGBits { last }; +typedef void* OpaqueExecContextPtr; +namespace pvt { +// As the concrete ExecutionContext is an implementation detail, +// it is placed in the pvt namespace. +// New accessor functions are provided below in the form +// OSL::get_???(const OpaqueExecContextPtr) +// Renderer's should use the accessor functions, and not attempt to cast or +// directly use the underlying ExecutionContext. This will allow the +// implemenation to change and possibly have accessors generated in llvm if +// needed. OSL library function implementions may directly use the +// ExecutionContext. +typedef ShaderGlobals ExecContext; +typedef ExecContext* ExecContextPtr; + +OSL_HOSTDEVICE inline ExecContextPtr +get_ec(OSL::OpaqueExecContextPtr oec) +{ + return reinterpret_cast(oec); +} +}; // namespace pvt + + + +template +OSL_HOSTDEVICE inline RenderStateT* +get_rs(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + auto rs = reinterpret_cast(ec->renderstate); + return rs; +} + +template +OSL_HOSTDEVICE inline TraceDataT* +get_tracedata(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + auto tracedata = reinterpret_cast(ec->tracedata); + return tracedata; +} + +template +OSL_HOSTDEVICE inline ObjectT* +get_objdata(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + auto objdata = reinterpret_cast(ec->objdata); + return objdata; +} + +// TODO: not sure ci should be exposed via a getter or not +// its presence here maybe temporary +OSL_HOSTDEVICE inline ClosureColor* +get_Ci(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->Ci; +} + +OSL_HOSTDEVICE inline TransformationPtr +get_object2common(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->object2common; +} + +OSL_HOSTDEVICE inline TransformationPtr +get_shader2common(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->shader2common; +} + +///Required by free function renderer services to process fmt specification calls; set by Shading System, and not by user +OSL_HOSTDEVICE inline int +get_shade_index(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->shade_index; +} + +///Required for memory allocation on a per thread basis for journaling fmt specification calls; set by Shading System, and not by user +OSL_HOSTDEVICE inline int +get_thread_index(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->thread_index; +} + +/// Surface position (and its x & y differentials). +OSL_HOSTDEVICE inline const Vec3& +get_P(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->P; +} + +OSL_HOSTDEVICE inline const Vec3& +get_dPdx(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->dPdx; +} + +OSL_HOSTDEVICE inline const Vec3& +get_dPdy(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->dPdy; +} + + +/// P's z differential, used for volume shading only. +OSL_HOSTDEVICE inline const Vec3& +get_dPdz(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->dPdz; +} + +/// Incident ray, and its x and y derivatives. +OSL_HOSTDEVICE inline const Vec3& +get_I(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->I; +} + +OSL_HOSTDEVICE inline const Vec3& +get_dIdx(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->dIdx; +} + +OSL_HOSTDEVICE inline const Vec3& +get_dIdy(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->dIdy; +} + + +/// Shading normal, already front-facing. +OSL_HOSTDEVICE inline const Vec3& +get_N(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->N; +} + +/// True geometric normal. +OSL_HOSTDEVICE inline const Vec3& +get_Ng(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->Ng; +} + +/// 2D surface parameter u, and its differentials. +OSL_HOSTDEVICE inline float +get_u(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->u; +} + +OSL_HOSTDEVICE inline float +get_dudx(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->dudx; +} + +OSL_HOSTDEVICE inline float +get_dudy(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->dudy; +} + +/// 2D surface parameter v, and its differentials. +OSL_HOSTDEVICE inline float +get_v(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->v; +} + +OSL_HOSTDEVICE inline float +get_dvdx(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->dvdx; +} + +OSL_HOSTDEVICE inline float +get_dvdy(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->dvdy; +} + +/// Surface tangents: derivative of P with respect to surface u and v. +OSL_HOSTDEVICE inline const Vec3& +get_dPdu(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->dPdu; +} + +OSL_HOSTDEVICE inline const Vec3& +get_dPdv(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->dPdv; +} + +/// Time for this shading sample. +OSL_HOSTDEVICE inline float +get_time(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->time; +} + +/// Time interval for the frame (or shading sample). +OSL_HOSTDEVICE inline float +get_dtime(const OpaqueExecContextPtr oec) +{ + auto ec = reinterpret_cast(oec); + return ec->dtime; +} + +/// Velocity vector: derivative of position P with respect to time. +OSL_HOSTDEVICE inline const Vec3& +get_dPdtime(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->dPdtime; +} + +/// For lights or light attenuation shaders: the point being illuminated +/// (Ps), and its differentials. +OSL_HOSTDEVICE inline const Vec3& +get_Ps(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->Ps; +} +OSL_HOSTDEVICE inline const Vec3& +get_dPsdx(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->dPsdx; +} +OSL_HOSTDEVICE inline const Vec3& +get_dPsdy(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->dPsdy; +} + + +/// If nonzero, we are shading the back side of a surface. +OSL_HOSTDEVICE inline int +get_backfacing(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->backfacing; +} + +/// If nonzero, will flip the result of calculatenormal(). +OSL_HOSTDEVICE inline int +get_flipHandedness(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->flipHandedness; +} + +/// Bit field of ray type flags. +OSL_HOSTDEVICE inline int +get_raytype(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->raytype; +} + +/// Surface area of the emissive object (used by light shaders for +/// energy normalization). +OSL_HOSTDEVICE inline float +get_surfacearea(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + return ec->surfacearea; +} + +namespace pvt { +// defined in opfmt.cpp +OSLEXECPUBLIC int +get_max_warnings_per_thread(const OSL::OpaqueExecContextPtr cptr); +} // namespace pvt + + +// Useful to pass to OSL::journal::Writer::record_warningfmt +inline int +get_max_warnings_per_thread(const OpaqueExecContextPtr oec) +{ + return pvt::get_max_warnings_per_thread(oec); +} + + + OSL_NAMESPACE_EXIT diff --git a/src/liboslcomp/typecheck.cpp b/src/liboslcomp/typecheck.cpp index 2fa0ea0164..83dc4d9f69 100644 --- a/src/liboslcomp/typecheck.cpp +++ b/src/liboslcomp/typecheck.cpp @@ -2246,6 +2246,7 @@ OSLCompilerImpl::type_from_code(const char* code, int* advance) case 'n': t = TypeDesc::TypeNormal; break; case 'm': t = TypeDesc::TypeMatrix; break; case 's': t = TypeDesc::TypeString; break; + case 'h': t = OSL::TypeUInt64; break; // ustringhash_pod case 'x': t = TypeDesc(TypeDesc::NONE); break; case 'X': t = TypeDesc(TypeDesc::PTR); break; case 'L': t = TypeDesc(TypeDesc::LONGLONG); break; diff --git a/src/liboslexec/CMakeLists.txt b/src/liboslexec/CMakeLists.txt index 663b6ab141..f620d63d0d 100644 --- a/src/liboslexec/CMakeLists.txt +++ b/src/liboslexec/CMakeLists.txt @@ -110,7 +110,7 @@ set (lib_src dictionary.cpp context.cpp instance.cpp loadshader.cpp master.cpp - opcolor.cpp opmatrix.cpp opmessage.cpp + opcolor.cpp opfmt.cpp opmatrix.cpp opmessage.cpp opnoise.cpp opspline.cpp opstring.cpp optexture.cpp oslexec.cpp diff --git a/src/liboslexec/backendllvm.cpp b/src/liboslexec/backendllvm.cpp index 04967e1c20..aa82fc9e7f 100644 --- a/src/liboslexec/backendllvm.cpp +++ b/src/liboslexec/backendllvm.cpp @@ -94,6 +94,8 @@ BackendLLVM::llvm_pass_type(const TypeSpec& typespec) lt = (llvm::Type*)ll.type_void_ptr(); else if (t == TypeDesc::LONGLONG) lt = ll.type_longlong(); + else if (t == OSL::TypeUInt64) + lt = ll.type_int64(); //LLVM does not recognize signed bits else { OSL_ASSERT_MSG(0, "not handling %s type yet", typespec.c_str()); } @@ -179,6 +181,8 @@ static ustring fields[] = { ustring("P"), ustring("objdata"), ustring("shadingcontext"), ustring("shadingStateUniform"), + ustring("thread_index"), + ustring("shade_index"), ustring("renderer"), ustring("object2common"), ustring("shader2common"), diff --git a/src/liboslexec/backendllvm.h b/src/liboslexec/backendllvm.h index 2f05be172f..93fe347902 100644 --- a/src/liboslexec/backendllvm.h +++ b/src/liboslexec/backendllvm.h @@ -145,12 +145,14 @@ class BackendLLVM final : public OSOProcessorBase { return llvm_load_string(ustring(str)); } + llvm::Value* llvm_load_stringhash(string_view str) + { + return llvm_load_stringhash(ustring(str)); + } + llvm::Value* llvm_load_stringhash(ustring str) { - const size_t size_t_bits = sizeof(size_t) * 8; - size_t p = str.hash(); - auto str_ = (size_t_bits == 64) ? ll.constant64(p) : ll.constant(int(p)); - return str_; + return ll.constant64(str.hash()); } /// Legacy version @@ -562,8 +564,10 @@ class BackendLLVM final : public OSOProcessorBase { /// entry in the groupdata struct. int find_userdata_index(const Symbol& sym); - void build_offsets_of_ShaderGlobals( - std::vector& offset_by_index); + // Helpers to export the actual data member offsets from LLVM's point of view + // of data structures that exist in C++ so we can validate the offsets match + void + build_offsets_of_ShaderGlobals(std::vector& offset_by_index); LLVM_Util ll; diff --git a/src/liboslexec/builtindecl.h b/src/liboslexec/builtindecl.h index e7a7110184..f620d4020c 100644 --- a/src/liboslexec/builtindecl.h +++ b/src/liboslexec/builtindecl.h @@ -116,11 +116,13 @@ DECL(osl_mul_closure_color, "CXCc") DECL(osl_allocate_closure_component, "CXii") DECL(osl_allocate_weighted_closure_component, "CXiiX") DECL(osl_closure_to_string, "sXC") +DECL(osl_closure_to_ustringhash, "hXC") DECL(osl_format, "ss*") -DECL(osl_printf, "xXs*") -DECL(osl_fprintf, "xXss*") -DECL(osl_error, "xXs*") -DECL(osl_warning, "xXs*") +DECL(osl_gen_ustringhash_pod, "hs") +DECL(osl_gen_printfmt, "xXhiXiX") +DECL(osl_gen_filefmt, "xXhhiXiX") +DECL(osl_gen_errorfmt, "xXhiXiX") +DECL(osl_gen_warningfmt, "xXhiXiX") DECL(osl_split, "isXsii") DECL(osl_incr_layers_executed, "xX") @@ -204,11 +206,11 @@ DECL(osl_dict_next, "iXi") DECL(osl_dict_value, "iXiXLX") DECL(osl_raytype_name, "iXs") #ifdef OSL_LLVM_NO_BITCODE -DECL(osl_range_check, "iiisXsisiss") +DECL(osl_range_check, "iiihXhihihh") #endif -DECL(osl_range_check_err, "iiisXsisiss") -DECL(osl_naninf_check, "xiXiXsisiis") -DECL(osl_uninit_check, "xLXXsisissisisii") +DECL(osl_range_check_err, "iiihXhihihh") +DECL(osl_naninf_check, "xiXiXhihiih") +DECL(osl_uninit_check, "xLXXhihihhihihii") DECL(osl_get_attribute, "iXissiiLX") DECL(osl_bind_interpolated_param, "iXsLiXiXiXi") DECL(osl_get_texture_options, "XX"); diff --git a/src/liboslexec/constfold.cpp b/src/liboslexec/constfold.cpp index b90ae2a0c7..9dff88fc7a 100644 --- a/src/liboslexec/constfold.cpp +++ b/src/liboslexec/constfold.cpp @@ -2215,11 +2215,8 @@ DECLFOLDER(constfold_transformc) } if (C.is_constant()) { Color3 Cin(C.get_float(0), C.get_float(1), C.get_float(2)); - // Color3 result = rop.shadingsys().colorsystem().transformc( - // from, to, Cin, rop.shadingcontext()); Color3 result = rop.shadingsys().colorsystem().transformc( from, to, Cin, rop.shaderglobals()); - rop.turn_into_assign(op, rop.add_constantc(result), "transformc => constant"); return 1; @@ -2419,7 +2416,7 @@ DECLFOLDER(constfold_gettextureinfo) ustringhash em; int result = rop.renderer()->get_texture_info( filename, nullptr, rop.shadingcontext()->texture_thread_info(), - rop.shadingcontext(), 0 /* TODO: subimage? */, dataname, t, mydata, + rop.shaderglobals(), 0 /* TODO: subimage? */, dataname, t, mydata, &em); ustring errormessage = ustring_from(em); // Now we turn diff --git a/src/liboslexec/context.cpp b/src/liboslexec/context.cpp index 750d4845ca..457891dbec 100644 --- a/src/liboslexec/context.cpp +++ b/src/liboslexec/context.cpp @@ -47,14 +47,13 @@ ShadingContext::ShadingContext(ShadingSystemImpl& shadingsys, : m_shadingsys(shadingsys) , m_renderer(m_shadingsys.renderer()) , m_group(NULL) - // , m_max_warnings(shadingsys.max_warnings_per_thread()) + , m_max_warnings(shadingsys.max_warnings_per_thread()) , m_dictionary(NULL) , batch_size_executed(0) { m_shadingsys.m_stat_contexts += 1; m_threadinfo = threadinfo ? threadinfo : shadingsys.get_perthread_info(); m_texture_thread_info = NULL; - shadingsys.m_shading_state_uniform.m_max_warnings = shadingsys.max_warnings_per_thread(); } @@ -72,9 +71,10 @@ ShadingContext::~ShadingContext() bool -ShadingContext::execute_init(ShaderGroup& sgroup, int threadindex, int shadeindex, - ShaderGlobals& ssg, void* userdata_base_ptr, - void* output_base_ptr, bool run) +ShadingContext::execute_init(ShaderGroup& sgroup, int threadindex, + int shadeindex, ShaderGlobals& ssg, + void* userdata_base_ptr, void* output_base_ptr, + bool run) { if (m_group) execute_cleanup(); @@ -134,7 +134,9 @@ ShadingContext::execute_init(ShaderGroup& sgroup, int threadindex, int shadeinde ssg.renderer = renderer(); ssg.Ci = NULL; ssg.thread_index = threadindex; - run_func(&ssg, m_heap.get(), userdata_base_ptr, output_base_ptr, threadindex, + ssg.shade_index = shadeindex; + //TODO: Possible remove shadeindex from run_func + run_func(&ssg, m_heap.get(), userdata_base_ptr, output_base_ptr, shadeindex, sgroup.interactive_arena_ptr()); } @@ -146,9 +148,9 @@ ShadingContext::execute_init(ShaderGroup& sgroup, int threadindex, int shadeinde bool -ShadingContext::execute_layer(int threadindex, int shadeindex, ShaderGlobals& ssg, - void* userdata_base_ptr, void* output_base_ptr, - int layernumber) +ShadingContext::execute_layer(int threadindex, int shadeindex, + ShaderGlobals& ssg, void* userdata_base_ptr, + void* output_base_ptr, int layernumber) { if (!group() || group()->nlayers() == 0 || group()->does_nothing()) return false; @@ -162,7 +164,7 @@ ShadingContext::execute_layer(int threadindex, int shadeindex, ShaderGlobals& ss if (!run_func) return false; - run_func(&ssg, m_heap.get(), userdata_base_ptr, output_base_ptr, threadindex, + run_func(&ssg, m_heap.get(), userdata_base_ptr, output_base_ptr, shadeindex, group()->interactive_arena_ptr()); if (profile) @@ -199,9 +201,9 @@ ShadingContext::execute_cleanup() bool -ShadingContext::execute(ShaderGroup& sgroup, int threadindex, int shadeindex, ShaderGlobals& ssg, - void* userdata_base_ptr, void* output_base_ptr, - bool run) +ShadingContext::execute(ShaderGroup& sgroup, int threadindex, int shadeindex, + ShaderGlobals& ssg, void* userdata_base_ptr, + void* output_base_ptr, bool run) { int n = sgroup.m_exec_repeat; Vec3 Psave, Nsave; // for repeats @@ -217,12 +219,12 @@ ShadingContext::execute(ShaderGroup& sgroup, int threadindex, int shadeindex, Sh bool result = true; while (1) { - if (!execute_init(sgroup, threadindex, shadeindex, ssg, userdata_base_ptr, - output_base_ptr, run)) + if (!execute_init(sgroup, threadindex, shadeindex, ssg, + userdata_base_ptr, output_base_ptr, run)) return false; if (run && n) - execute_layer(threadindex, shadeindex, ssg, userdata_base_ptr, output_base_ptr, - group()->nlayers() - 1); + execute_layer(threadindex, shadeindex, ssg, userdata_base_ptr, + output_base_ptr, group()->nlayers() - 1); result = execute_cleanup(); if (--n < 1) break; // done diff --git a/src/liboslexec/dictionary.cpp b/src/liboslexec/dictionary.cpp index 6ae2ea0974..aad1d2d959 100644 --- a/src/liboslexec/dictionary.cpp +++ b/src/liboslexec/dictionary.cpp @@ -19,6 +19,7 @@ namespace pugi = OIIO::pugi; #include "oslexec_pvt.h" +#include OSL_NAMESPACE_ENTER @@ -58,8 +59,8 @@ class Dictionary { delete doc; } - int dict_find(ustring dictionaryname, ustring query); - int dict_find(int nodeID, ustring query); + int dict_find(ExecContextPtr ec, ustring dictionaryname, ustring query); + int dict_find(ExecContextPtr ec, int nodeID, ustring query); int dict_next(int nodeID); int dict_value(int nodeID, ustring attribname, TypeDesc type, void* data); @@ -138,13 +139,13 @@ class Dictionary { std::vector m_stringdata; // Helper function: return the document index given dictionary name. - int get_document_index(ustring dictionaryname); + int get_document_index(ExecContextPtr ec, ustring dictionaryname); }; int -Dictionary::get_document_index(ustring dictionaryname) +Dictionary::get_document_index(ExecContextPtr ec, ustring dictionaryname) { DocMap::iterator dm = m_document_map.find(dictionaryname); int dindex; @@ -162,9 +163,8 @@ Dictionary::get_document_index(ustring dictionaryname) parse_result = doc->load_string(dictionaryname.c_str()); } if (!parse_result) { - m_context->errorfmt("XML parsed with errors: {}, at offset {}", - parse_result.description(), - parse_result.offset); + OSL::errorfmt(ec, "XML parsed with errors: {}, at offset {}", + parse_result.description(), parse_result.offset); m_document_map[dictionaryname] = -1; return -1; } @@ -179,9 +179,9 @@ Dictionary::get_document_index(ustring dictionaryname) int -Dictionary::dict_find(ustring dictionaryname, ustring query) +Dictionary::dict_find(ExecContextPtr ec, ustring dictionaryname, ustring query) { - int dindex = get_document_index(dictionaryname); + int dindex = get_document_index(ec, dictionaryname); if (dindex < 0) return dindex; @@ -199,8 +199,7 @@ Dictionary::dict_find(ustring dictionaryname, ustring query) try { matches = doc->select_nodes(query.c_str()); } catch (const pugi::xpath_exception& e) { - m_context->errorfmt("Invalid dict_find query '{}': {}", query, - e.what()); + OSL::errorfmt(ec, "Invalid dict_find query '{}': {}", query, e.what()); return 0; } @@ -228,7 +227,7 @@ Dictionary::dict_find(ustring dictionaryname, ustring query) int -Dictionary::dict_find(int nodeID, ustring query) +Dictionary::dict_find(ExecContextPtr ec, int nodeID, ustring query) { if (nodeID <= 0 || nodeID >= (int)m_nodes.size()) return 0; // invalid node ID @@ -245,8 +244,7 @@ Dictionary::dict_find(int nodeID, ustring query) try { matches = m_nodes[nodeID].node.select_nodes(query.c_str()); } catch (const pugi::xpath_exception& e) { - m_context->errorfmt("Invalid dict_find query '{}': {}", query, - e.what()); + OSL::errorfmt(ec, "Invalid dict_find query '{}': {}", query, e.what()); return 0; } @@ -379,23 +377,24 @@ Dictionary::dict_value(int nodeID, ustring attribname, TypeDesc type, int -ShadingContext::dict_find(ustring dictionaryname, ustring query) +ShadingContext::dict_find(ExecContextPtr ec, ustring dictionaryname, + ustring query) { if (!m_dictionary) { m_dictionary = new Dictionary(this); } - return m_dictionary->dict_find(dictionaryname, query); + return m_dictionary->dict_find(ec, dictionaryname, query); } int -ShadingContext::dict_find(int nodeID, ustring query) +ShadingContext::dict_find(ExecContextPtr ec, int nodeID, ustring query) { if (!m_dictionary) { m_dictionary = new Dictionary(this); } - return m_dictionary->dict_find(nodeID, query); + return m_dictionary->dict_find(ec, nodeID, query); } @@ -430,38 +429,38 @@ ShadingContext::free_dict_resources() OSL_SHADEOP int -osl_dict_find_iis(void* sg_, int nodeID, void* query) +osl_dict_find_iis(OpaqueExecContextPtr oec, int nodeID, void* query) { - ShaderGlobals* sg = (ShaderGlobals*)sg_; - return sg->context->dict_find(nodeID, USTR(query)); + auto ec = pvt::get_ec(oec); + return ec->context->dict_find(ec, nodeID, USTR(query)); } OSL_SHADEOP int -osl_dict_find_iss(void* sg_, void* dictionary, void* query) +osl_dict_find_iss(OpaqueExecContextPtr oec, void* dictionary, void* query) { - ShaderGlobals* sg = (ShaderGlobals*)sg_; - return sg->context->dict_find(USTR(dictionary), USTR(query)); + auto ec = pvt::get_ec(oec); + return ec->context->dict_find(ec, USTR(dictionary), USTR(query)); } OSL_SHADEOP int -osl_dict_next(void* sg_, int nodeID) +osl_dict_next(OpaqueExecContextPtr oec, int nodeID) { - ShaderGlobals* sg = (ShaderGlobals*)sg_; - return sg->context->dict_next(nodeID); + auto ec = pvt::get_ec(oec); + return ec->context->dict_next(nodeID); } OSL_SHADEOP int -osl_dict_value(void* sg_, int nodeID, void* attribname, long long type, - void* data) +osl_dict_value(OpaqueExecContextPtr oec, int nodeID, void* attribname, + long long type, void* data) { - ShaderGlobals* sg = (ShaderGlobals*)sg_; - return sg->context->dict_value(nodeID, USTR(attribname), TYPEDESC(type), + auto ec = pvt::get_ec(oec); + return ec->context->dict_value(nodeID, USTR(attribname), TYPEDESC(type), data); } diff --git a/src/liboslexec/journal.cpp b/src/liboslexec/journal.cpp index d61188f897..6d9c7e29d9 100644 --- a/src/liboslexec/journal.cpp +++ b/src/liboslexec/journal.cpp @@ -3,311 +3,437 @@ // https://github.com/AcademySoftwareFoundation/OpenShadingLanguage -#include #include #include +#include + +#include +#include OSL_NAMESPACE_ENTER -namespace journal +int +decode_message(uint64_t format_hash, int32_t arg_count, + const EncodedType* arg_types, const uint8_t* arg_values, + std::string& built_str) { + // set max size of each output string + // replacement region buffer + char rr_buf[128]; + built_str.clear(); + + const char* format = OSL::ustring::from_hash(format_hash).c_str(); + OSL_ASSERT(format != nullptr + && "The string should have been a valid ustring"); + const int len = static_cast(strlen(format)); + + int arg_index = 0; + int arg_offset = 0; + constexpr size_t rs_max_length = 1024; + char replacement_str[rs_max_length]; + for (int j = 0; j < len;) { + // If we encounter a '%', then we'll copy the format string to 'fmt_string' + // and provide that to printf() directly along with a pointer to the argument + // we're interested in printing. + char cur_char = format[j++]; + if (cur_char == '{') { + bool is_rr_complete = false; + rr_buf[0] = cur_char; + int rr_len = 1; + do { + char next_char = format[j++]; + + if ((rr_len == 1) && next_char == '{') { + OSL_DASSERT((rr_buf[0] == '{')); + // Not a replacement region, but an escaped { + // We don't want to copy over {{, just { + // so we will just eat the 2nd { + break; + } + rr_buf[rr_len++] = next_char; -// TODO: update hashcode variable name to format_hash -void construct_message(uint64_t format_hash, int32_t arg_count, - const EncodedType *argTypes/*(&argTypes)[128]*/, uint32_t argValuesSize, - uint8_t *argValues/*(&argValues)[4096]*/, std::string &built_str) -{ + if (next_char == '}') { + is_rr_complete = true; + } + } while (!is_rr_complete && j < len + && rr_len < static_cast(sizeof(rr_buf))); + OSL::string_view replacement_region { rr_buf, size_t(rr_len) }; - // set max size of each output string - // replacement region buffer - char rr_buf[128]; - built_str.clear(); - - const char* format = OSL::ustring::from_hash(format_hash).c_str(); - - OSL_ASSERT(format != nullptr - && "The string should have been a valid ustring"); - const int len = static_cast(strlen(format)); - - int arg_index = 0; - int arg_offset = 0; - - constexpr size_t rs_max_length = 1024; - char replacement_str[rs_max_length]; - - - for (int j = 0; j < len; j++) { - // If we encounter a '%', then we'll copy the format string to 'fmt_string' - // and provide that to printf() directly along with a pointer to the argument - // we're interested in printing. - if (format[j] == '{' && (j==0 || format[j-1] != '\\')) { - int rr_len=0; - for (;j < len && rr_len < static_cast(sizeof(rr_buf));++j, ++rr_len) - { - - rr_buf[rr_len] = format[j]; - - } while (j < len && rr_len < static_cast(sizeof(rr_buf)) ); - OSL::string_view replacementRegion{rr_buf, size_t(rr_len)}; - //OSL::string_view replacementRegion{rr_buf, size_t(rr_len)}; + if (!is_rr_complete) { + built_str += replacement_region; + } else { if (arg_index < arg_count) { - EncodedType arg_type = argTypes[arg_index]; - - // Avoid "error: ‘void* memcpy(void*, const void*, size_t)’ writing to an object of type ‘class OpenImageIO_v2_3::ustringhash’ with no trivial copy-assignment; use copy-assignment or copy-initialization instead" - // TODO: remove diagnostic workaround once OIIO::ustringhash is changed such that - // static_assert(std::is_trivially_copyable::value, "Make ustringhash::ustringhash(const ustringhash&) = default;"); - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wclass-memaccess" - switch(arg_type) { - case EncodedType::kUstringHash: { - OSL::ustringhash arg_value; - memcpy(&arg_value, &argValues[arg_offset], sizeof(arg_value)); - const char* arg_string = arg_value.c_str(); - - auto result = OSL::fmtformat_to_n(replacement_str, rs_max_length, - replacementRegion, arg_string); - *result.out = '\0'; - - - } - break; - case EncodedType::kInt32: { - int32_t arg_value; - memcpy(&arg_value, &argValues[arg_offset], sizeof(arg_value)); - auto result = OSL::fmtformat_to_n(replacement_str, 4, replacementRegion, arg_value); - *result.out = '\0'; - - } - break; - case EncodedType::kFloat: { - float arg_value; - memcpy(&arg_value, &argValues[arg_offset], sizeof(arg_value)); - auto result = OSL::fmtformat_to_n(replacement_str, rs_max_length, replacementRegion, arg_value); - *result.out = '\0'; - } - break; - case EncodedType::kDouble: { - double arg_value; - memcpy(&arg_value, &argValues[arg_offset], sizeof(arg_value)); - auto result = OSL::fmtformat_to_n(replacement_str, rs_max_length, replacementRegion, arg_value); - *result.out = '\0'; - } - break; + EncodedType arg_type = arg_types[arg_index]; + + +#if OSL_GNUC_VERSION >= 90000 +// ignore -Wclass-memaccess to avoid "error: ‘void* memcpy(void*, const void*, size_t)’ writing to an object of type ‘class OpenImageIO_v2_3::ustringhash’ +// with no trivial copy-assignment; use copy-assignment or copy-initialization instead" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wclass-memaccess" + // TODO: remove diagnostic workaround once OIIO::ustringhash is changed such that + // static_assert(std::is_trivially_copyable::value, "Make ustringhash::ustringhash(const ustringhash&) = default;"); +#endif + switch (arg_type) { + case EncodedType::kUstringHash: { + OSL::ustringhash arg_value; + memcpy(&arg_value, &arg_values[arg_offset], + sizeof(arg_value)); + const char* arg_string = arg_value.c_str(); + auto result = OSL::fmtformat_to_n(replacement_str, + rs_max_length + 1, + replacement_region, + arg_string); + *result.out = '\0'; + } break; + case EncodedType::kInt32: { + int32_t arg_value; + memcpy(&arg_value, &arg_values[arg_offset], + sizeof(arg_value)); + auto result = OSL::fmtformat_to_n(replacement_str, + rs_max_length, + replacement_region, + arg_value); + *result.out = '\0'; + } break; + case EncodedType::kFloat: { + float arg_value; + memcpy(&arg_value, &arg_values[arg_offset], + sizeof(arg_value)); + auto result = OSL::fmtformat_to_n(replacement_str, + rs_max_length, + replacement_region, + arg_value); + *result.out = '\0'; + } break; + case EncodedType::kDouble: { + double arg_value; + memcpy(&arg_value, &arg_values[arg_offset], + sizeof(arg_value)); + auto result = OSL::fmtformat_to_n(replacement_str, + rs_max_length, + replacement_region, + arg_value); + *result.out = '\0'; + } break; + case EncodedType::kInt64: { + int64_t arg_value; + memcpy(&arg_value, &arg_values[arg_offset], + sizeof(arg_value)); + auto result = OSL::fmtformat_to_n(replacement_str, + rs_max_length, + replacement_region, + arg_value); + *result.out = '\0'; + } break; + case EncodedType::kUInt32: { + uint32_t arg_value; + memcpy(&arg_value, &arg_values[arg_offset], + sizeof(arg_value)); + auto result = OSL::fmtformat_to_n(replacement_str, + rs_max_length, + replacement_region, + arg_value); + *result.out = '\0'; + } break; + case EncodedType::kUInt64: { + uint64_t arg_value; + memcpy(&arg_value, &arg_values[arg_offset], + sizeof(arg_value)); + auto result = OSL::fmtformat_to_n(replacement_str, + rs_max_length, + replacement_region, + arg_value); + *result.out = '\0'; + } break; + + case EncodedType::kPointer: { + const void* arg_value; + memcpy(&arg_value, &arg_values[arg_offset], + sizeof(arg_value)); + auto result = OSL::fmtformat_to_n(replacement_str, + rs_max_length, + replacement_region, + arg_value); + *result.out = '\0'; + } break; + + case EncodedType::kTypeDesc: { + OSL::TypeDesc arg_value; + memcpy(&arg_value, &arg_values[arg_offset], + sizeof(arg_value)); + auto result = OSL::fmtformat_to_n(replacement_str, + rs_max_length, + replacement_region, + arg_value); + *result.out = '\0'; + } break; + default: OSL_ASSERT(0 && "unhandled EncodedType"); }; - #pragma GCC diagnostic pop +#if OSL_GNUC_VERSION >= 90000 +# pragma GCC diagnostic pop +#endif - arg_offset += SizeByEncodedType[static_cast(arg_type)]; + arg_offset += pvt::size_of_encoded_type(arg_type); ++arg_index; - built_str += replacement_str; + built_str += replacement_str; } - } else { - built_str += format[j]; } - } - } - + } else { + //if we are not "{" for printf; all others contain {} as part of the message + built_str += cur_char; + if (cur_char == '}' && j < len && format[j] == '}') { + // }} should just be output as } + // so skip the next character + ++j; + } + } //else within for -bool initialize_buffer(uint8_t * const buffer, uint32_t buf_size_, uint32_t page_size_, int thread_count_) + } //initial for loop + return arg_offset; +} +namespace journal { - Organization & org = *(reinterpret_cast(buffer)); - org.thread_count = thread_count_; - org.buf_size = buf_size_; - org.page_size = page_size_; - - - PageInfo *pageinfo_by_thread_index = reinterpret_cast(buffer + sizeof(Organization)); - - org.buf_pos = org.calc_end_of_page_infos() + org.page_size * org.thread_count; +bool +initialize_buffer(uint8_t* const buffer, uint32_t buf_size, + uint32_t page_size, int thread_count) - - - if (org.buf_pos > org.buf_size) { - +{ + using namespace journal::pvt; + auto& org = *(reinterpret_cast(buffer)); + org.thread_count = thread_count; + org.buf_size = buf_size; + org.page_size = page_size; + + org.additional_bytes_required = 0; + org.exceeded_page_size = 0; + org.free_pos = org.calc_end_of_page_infos() + // Pre-allocate 1 page per thread + + org.page_size * org.thread_count; + + if (org.free_pos > org.buf_size) { return false; } - for(int thread_index=0;thread_index < org.thread_count; ++thread_index) { - PageInfo &info = pageinfo_by_thread_index[thread_index]; - info.pos = org.calc_head_pos(thread_index); + // Populate each thread's initial PageInfo + for (int thread_index = 0; thread_index < org.thread_count; + ++thread_index) { + PageInfo& info = org.get_pageinfo(thread_index); + + info.pos = org.calc_head_pos(thread_index); info.remaining = org.page_size; - + info.warning_count = 0; } - - return true; } - -TrackRecentlyReported::TrackRecentlyReported(bool limit_errors = true, int max_error_count=32, - bool limit_warnings = true, int max_warning_count=32 - ) +TrackRecentlyReported::TrackRecentlyReported(bool limit_errors, + int error_history_capacity, + bool limit_warnings, + int warning_history_capacity) : m_limit_errors(limit_errors) - , m_max_error_count(max_error_count) + , m_error_history_capacity(error_history_capacity) , m_limit_warnings(limit_warnings) - , m_max_warning_count(max_warning_count) - { - - } + , m_warning_history_capacity(warning_history_capacity) +{ +} -bool TrackRecentlyReported::shouldReportError(const OSL::string_view & message) - { - int n = 0; - if (!m_limit_errors) - return true; - for (auto&& s : m_errseen) { - if (s == message) - return false; - ++n; - } - if (n >= m_max_error_count) - m_errseen.pop_front(); - m_errseen.push_back(message); +bool +TrackRecentlyReported::shouldReportError(const OSL::string_view& message) +{ + int n = 0; + if (!m_limit_errors) return true; + for (auto&& s : m_errseen) { + if (s == message) + return false; + ++n; } + if (n >= m_error_history_capacity) + m_errseen.pop_front(); + m_errseen.push_back(message); + return true; +} -bool TrackRecentlyReported::shouldReportWarning(const OSL::string_view & message) - { - int n = 0; - if (!m_limit_errors) - return true; - for (auto&& s : m_warnseen) { - if (s == message) - return false; - ++n; - } - if (n >= m_max_error_count) - m_warnseen.pop_front(); - m_warnseen.push_back(message); +bool +TrackRecentlyReported::shouldReportWarning(const OSL::string_view& message) +{ + int n = 0; + if (!m_limit_errors) return true; + for (auto&& s : m_warnseen) { + if (s == message) + return false; + ++n; } + if (n >= m_warning_history_capacity) + m_warnseen.pop_front(); + m_warnseen.push_back(message); + return true; +} -Report2ErrorHandler::Report2ErrorHandler(OSL::ErrorHandler *eh, TrackRecentlyReported m_tracker) : m_eh(eh), m_tracker(m_tracker) {} - -void Report2ErrorHandler::report_error(int thread_index, int shade_index, const OSL::string_view & message) -{ - if (m_tracker.shouldReportError(message)) - { - m_eh->error(std::string(message)); - } +Report2ErrorHandler::Report2ErrorHandler(OSL::ErrorHandler* eh, + TrackRecentlyReported& tracker) + : m_eh(eh), m_tracker(tracker) +{ +} + +void +Report2ErrorHandler::report_error(int thread_index, int shade_index, + const OSL::string_view& message) +{ + if (m_tracker.shouldReportError(message)) { + m_eh->error(std::string(message)); + } } -void Report2ErrorHandler::report_warning(int thread_index, int shade_index, const OSL::string_view & message) -{ - - if (m_tracker.shouldReportWarning(message)) - { +void +Report2ErrorHandler::report_warning(int thread_index, int shade_index, + const OSL::string_view& message) +{ + if (m_tracker.shouldReportWarning(message)) { m_eh->warning(std::string(message)); - } + } } -void Report2ErrorHandler::report_print(int thread_index, int shade_index, const OSL::string_view & message) -{ - m_eh->message(message); +void +Report2ErrorHandler::report_print(int thread_index, int shade_index, + const OSL::string_view& message) +{ + m_eh->message(message); } -void Report2ErrorHandler::report_file_print(int thread_index, int shade_index, const OSL::string_view & filename, const OSL::string_view & message) +void +Report2ErrorHandler::report_file_print(int thread_index, int shade_index, + const OSL::string_view& filename, + const OSL::string_view& message) { // NOTE: behavior change for OSL runtime, we will no longer open files by default - // but instead just prefix the fprintf message with the filename and pass it along + // but instead just prefix the fprintf message with the filename and pass it along // as a regular message. // A renderer is free to override report_fprintf and open files under its own purview - - m_eh->message(OSL::fmtformat("{}:{}", filename, message)); + m_eh->message(OSL::fmtformat("{}:{}", filename, message)); } -Reader::Reader(const uint8_t * buffer_, Reporter &reporter) - : m_buffer(buffer_), - m_org(*(reinterpret_cast(buffer_))), - m_pageinfo_by_thread_index ( reinterpret_cast(buffer_ + sizeof(Organization))), - m_reporter(reporter) - {} - - void Reader::process() - { - const int tc = m_org.thread_count; - for (int thread_index=0; thread_index < tc; ++thread_index) { - process_entries_for_thread(thread_index); - } +Reader::Reader(const uint8_t* buffer_, Reporter& reporter) + : m_buffer(buffer_) + , m_org(*(reinterpret_cast(buffer_))) + , m_pageinfo_by_thread_index( + reinterpret_cast(buffer_ + sizeof(pvt::Organization))) + , m_reporter(reporter) +{ +} + +void +Reader::process() +{ + const int tc = m_org.thread_count; + for (int thread_index = 0; thread_index < tc; ++thread_index) { + process_entries_for_thread(thread_index); } + if (m_org.additional_bytes_required != 0) { + std::string overfill_message = OSL::fmtformat( + "Journal sized {} bytes couldn't capture all prints, warnings, and errors. Additional {} bytes would be required", + m_org.buf_size, m_org.additional_bytes_required); + m_reporter.report_warning(-1, -1, overfill_message); + } + if (m_org.exceeded_page_size != 0) { + std::string exceeded_message = OSL::fmtformat( + "Journal page size {} exceeded, largest individual message sized {} bytes. Consider increasing your page size.", + m_org.page_size, m_org.exceeded_page_size); + m_reporter.report_warning(-1, -1, exceeded_message); + } +} - void Reader::process_entries_for_thread(int thread_index) - { - uint32_t read_pos = m_org.calc_head_pos(thread_index); - const PageInfo &info = m_pageinfo_by_thread_index[thread_index]; - // We are done processing entries when our read_pos reaches the end_pos; - uint32_t end_pos = info.pos; - - std::string message; - message.reserve(m_org.page_size); - int shade_index; - auto decodeMessage = [&](const uint8_t *src_ptr)->void { - uint64_t format_hash; - int32_t arg_count; - EncodedType arg_types[128]; - uint8_t arg_values[4096]; - memcpy(&shade_index, src_ptr + sizeof(Content), sizeof(shade_index)); - memcpy(&format_hash, src_ptr + sizeof(Content) + sizeof(shade_index), sizeof(format_hash)); - memcpy(&arg_count, src_ptr + sizeof(Content) + sizeof(shade_index) + sizeof(format_hash), sizeof(arg_count)); - memcpy(arg_types, src_ptr + sizeof(Content) + sizeof(shade_index) + sizeof(format_hash) + sizeof(arg_count), sizeof(EncodedType)*arg_count); - uint32_t arg_values_size = 0u; - for(int arg_index=0; arg_index < arg_count; ++arg_index) { - arg_values_size += SizeByEncodedType[static_cast(arg_types[arg_index])]; - } - memcpy(arg_values, src_ptr + sizeof(Content) + sizeof(shade_index) + sizeof(format_hash) + sizeof(arg_count) + sizeof(EncodedType)*arg_count, arg_values_size); - read_pos += sizeof(Content) + sizeof(shade_index) + sizeof(format_hash) + sizeof(arg_count) + sizeof(EncodedType)*arg_count + arg_values_size; - - const char* format_string = OSL::ustring::from_hash(format_hash).c_str(); - - - construct_message(format_hash, arg_count, &arg_types[0], arg_values_size, - &arg_values[0], message); - }; - - while(read_pos !=end_pos) { - const uint8_t *src_ptr = m_buffer + read_pos; - - - Content content; - memcpy(&content, src_ptr, sizeof(content)); - switch(content) { - case Content::PageTransition: { - uint32_t next_pos; - memcpy(&next_pos, src_ptr + sizeof(content), sizeof(content)); - read_pos = next_pos; - } - break; - case Content::Error: { - decodeMessage(src_ptr); - m_reporter.report_error(thread_index, shade_index, message); - } - break; - case Content::Warning: { - decodeMessage(src_ptr); - m_reporter.report_warning(thread_index, shade_index, message); - } - break; - case Content::Print: { - decodeMessage(src_ptr); - m_reporter.report_print(thread_index, shade_index, message); - } - break; - case Content::FilePrint: { - decodeMessage(src_ptr); - uint64_t filname_hash; - memcpy(&filname_hash, m_buffer + read_pos, sizeof(filname_hash)); - read_pos += sizeof(filname_hash); - m_reporter.report_file_print(thread_index, shade_index, OSL::ustring::from_hash(filname_hash), message); - } - break; - }; +void +Reader::process_entries_for_thread(int thread_index) +{ + uint32_t read_pos = m_org.calc_head_pos(thread_index); + const auto& info = m_pageinfo_by_thread_index[thread_index]; + // We are done processing entries when our read_pos reaches the end_pos; + uint32_t end_pos = info.pos; + + using pvt::Content; + + std::string message; + message.reserve(m_org.page_size); + int shade_index; + auto decodeMessage = [&](const uint8_t* src_ptr) -> void { + memcpy(&shade_index, src_ptr + sizeof(Content), sizeof(shade_index)); + uint64_t format_hash; + memcpy(&format_hash, src_ptr + sizeof(Content) + sizeof(shade_index), + sizeof(format_hash)); + int32_t arg_count; + memcpy(&arg_count, + src_ptr + sizeof(Content) + sizeof(shade_index) + + sizeof(format_hash), + sizeof(arg_count)); + + auto arg_types = reinterpret_cast(src_ptr + sizeof(Content) + sizeof(shade_index) + + sizeof(format_hash) + sizeof(arg_count)); + + const uint8_t *arg_values = src_ptr + sizeof(Content) + sizeof(shade_index) + + sizeof(format_hash) + sizeof(arg_count) + + sizeof(EncodedType) * arg_count; + int arg_values_size = decode_message(format_hash, arg_count, arg_types, + arg_values, message); + read_pos += sizeof(Content) + sizeof(shade_index) + sizeof(format_hash) + + sizeof(arg_count) + sizeof(EncodedType) * arg_count + + arg_values_size; + + }; + + while (read_pos != end_pos) { + const uint8_t* src_ptr = m_buffer + read_pos; + + Content content; + memcpy(&content, src_ptr, sizeof(content)); + switch (content) { + case Content::PageTransition: { + uint32_t next_pos; + memcpy(&next_pos, src_ptr + sizeof(content), sizeof(next_pos)); + + read_pos = next_pos; + break; + } + + case Content::Error: { + decodeMessage(src_ptr); + m_reporter.report_error(thread_index, shade_index, message); + break; } + + case Content::Warning: { + decodeMessage(src_ptr); + m_reporter.report_warning(thread_index, shade_index, message); + break; + } + + case Content::Print: { + decodeMessage(src_ptr); + m_reporter.report_print(thread_index, shade_index, message); + break; + } + + case Content::FilePrint: { + decodeMessage(src_ptr); + uint64_t filname_hash; + memcpy(&filname_hash, m_buffer + read_pos, sizeof(filname_hash)); + read_pos += sizeof(filname_hash); + m_reporter.report_file_print(thread_index, shade_index, + OSL::ustring::from_hash(filname_hash), + message); + break; + } + }; } +} -} //namespace journal +} //namespace journal OSL_NAMESPACE_EXIT \ No newline at end of file diff --git a/src/liboslexec/llvm_gen.cpp b/src/liboslexec/llvm_gen.cpp index e5adc74eb6..ab7f3baaed 100644 --- a/src/liboslexec/llvm_gen.cpp +++ b/src/liboslexec/llvm_gen.cpp @@ -79,10 +79,17 @@ LLVMGEN(llvm_gen_generic); void BackendLLVM::llvm_gen_debug_printf(string_view message) { - ustring s = ustring::fmtformat("({} {}) {}", inst()->shadername(), + // Bake everything into the format specifier string instead of + // passing arguments. + ustring s = ustring::fmtformat("({} {}) {}\n", inst()->shadername(), inst()->layername(), message); - ll.call_function("osl_printf", sg_void_ptr(), ll.constant("%s\n"), - ll.constant(s)); + + llvm::Value* valargs[] + = { sg_void_ptr(), llvm_load_stringhash(s), + ll.constant(0) /*arg_count*/, ll.void_ptr_null() /*arg_types*/, + ll.constant(0) /*arg_values_size*/, ll.void_ptr_null() /*arg_values*/ }; + + ll.call_function("osl_gen_printfmt", valargs); } @@ -90,8 +97,14 @@ BackendLLVM::llvm_gen_debug_printf(string_view message) void BackendLLVM::llvm_gen_warning(string_view message) { - ll.call_function("osl_warning", sg_void_ptr(), ll.constant("%s\n"), - ll.constant(message)); + // Bake everything into the format specifier string instead of + // passing arguments. + ustring s = ustring::fmtformat("{}\n", message); + llvm::Value* valargs[] + = { sg_void_ptr(), llvm_load_stringhash(s), + ll.constant(0) /*arg_count*/, ll.void_ptr_null() /*arg_types*/, + ll.constant(0) /*arg_values_size*/, ll.void_ptr_null() /*arg_values*/ }; + ll.call_function("osl_gen_warningfmt", valargs); } @@ -99,8 +112,14 @@ BackendLLVM::llvm_gen_warning(string_view message) void BackendLLVM::llvm_gen_error(string_view message) { - ll.call_function("osl_error", sg_void_ptr(), ll.constant("%s\n"), - ll.constant(message)); + // Bake everything into the format specifier string instead of + // passing arguments. + ustring s = ustring::fmtformat("{}\n", message); + llvm::Value* valargs[] + = { sg_void_ptr(), llvm_load_stringhash(s), + ll.constant(0) /*arg_count*/, ll.void_ptr_null() /*arg_types*/, + ll.constant(0) /*arg_values_size*/, ll.void_ptr_null() /*arg_values*/ }; + ll.call_function("osl_gen_errorfmt", valargs); } @@ -252,6 +271,7 @@ LLVMGEN(llvm_gen_useparam) } + // Used for printf, error, warning, format, fprintf LLVMGEN(llvm_gen_printf_legacy) { @@ -275,7 +295,7 @@ LLVMGEN(llvm_gen_printf_legacy) // For some ops, we push the shader globals pointer if (op.opname() == op_printf || op.opname() == op_error || op.opname() == op_warning || op.opname() == op_fprintf) - call_args.push_back(rop.sg_void_ptr()); //arg0: sg + call_args.push_back(rop.sg_void_ptr()); // fprintf also needs the filename if (op.opname() == op_fprintf) { @@ -292,7 +312,6 @@ LLVMGEN(llvm_gen_printf_legacy) ustring format_ustring = format_sym.get_string(); const char* format = format_ustring.c_str(); std::string s; - //ustring s; int arg = format_arg + 1; size_t optix_size = 0; // how much buffer size does optix need? while (*format != '\0') { @@ -483,8 +502,8 @@ LLVMGEN(llvm_gen_print_fmt) Opcode& op(rop.inst()->ops()[opnum]); // The format op is currently handled by llvm_gen_printf_legacy, - // but could be moved here in future - // NOTE: format would not a callthrough to renderservices, + // but could be moved here in future + // NOTE: format would not a callthrough to renderservices, // but should be handled in opstring.cpp OSL_ASSERT(op.opname() != op_format); @@ -492,8 +511,9 @@ LLVMGEN(llvm_gen_print_fmt) // Which argument is the format string? Usually 0, but for op // format() and fprintf(), the formatting string is argument #1. - int format_arg = (op.opname() == op_format || op.opname() == op_fprintf) ? 1 - : 0; + int format_arg = (op.opname() == op_format || op.opname() == op_fprintf) + ? 1 + : 0; Symbol& format_sym = *rop.opargsym(op, format_arg); std::vector call_args; @@ -503,33 +523,36 @@ LLVMGEN(llvm_gen_print_fmt) return false; } - call_args.push_back(rop.sg_void_ptr()); //arg0: sg - //call_args.push_back(rop.ll.constant_ptr(NULL)); //arg0: sg + call_args.push_back(rop.sg_void_ptr()); // fprintf also needs the filename if (op.opname() == op_fprintf) { - Symbol& Filename = *rop.opargsym(op, 0); - llvm::Value* fn = rop.llvm_load_value(Filename); - call_args.push_back(fn); //arg1: filename only for frintf + Symbol& Filename = *rop.opargsym(op, 0); + ustring filename_ustring = Filename.get_string(); + call_args.push_back( + rop.llvm_load_stringhash(filename_ustring)); //filename } + // We're going to need to adjust the format string as we go, but I'd + // like to reserve a spot for the char*. + // size_t new_format_slot = call_args.size(); + // call_args.push_back(NULL); + ustring format_ustring = format_sym.get_string(); - const char* format = format_ustring.c_str(); + const char* format + = format_ustring.c_str(); //contains all the printf formating characters std::string s; - int arg = format_arg + 1; - size_t optix_size = 0; // how much buffer size does optix need? - //SM: Example call: printf("The values at %s is %d, %f, %6.2f", "marble", 5, 6.4, 123.456); - std::vector encodedTypes; - // uint32_t argValuesSize = 0u; - int argValuesSize = 0u; - - std::vector loadedArgValues; - + int arg = format_arg + 1; + // Example call: printf("The values at %s is %d, %f, %6.2f", "marble", 5, 6.4, 123.456); + std::vector encodedtypes; + int arg_values_size = 0u; + std::vector loaded_arg_values; while (*format != '\0') { if (*format == '%') { if (format[1] == '%') { // '%%' is a literal '%' - s += "%%"; + // The fmtlib expects just a single % + s += "%"; format += 2; // skip both percentages continue; } @@ -538,8 +561,10 @@ LLVMGEN(llvm_gen_print_fmt) && *format != 'f' && *format != 'g' && *format != 'i' && *format != 'm' && *format != 'n' && *format != 'o' && *format != 'p' && *format != 's' && *format != 'u' - && *format != 'v' && *format != 'x' && *format != 'X') + && *format != 'v' && *format != 'x' && *format != 'X') { ++format; + } + char formatchar = *format++; // Also eat the format char if (arg >= op.nargs()) { rop.shadingcontext()->errorfmt( @@ -549,10 +574,24 @@ LLVMGEN(llvm_gen_print_fmt) } std::string ourformat(oldfmt, format); // straddle the format + + // printf specifier uses - to indicate left justified alignment and ignores extra - chars present + // libfmt specifier uses < to indicate left justified alignment and does not ignore extra chars + // so change - to < and erase any extraneous - + auto pos_of_minus = ourformat.find_first_of('-'); + if (pos_of_minus != std::string::npos) { + ourformat.replace(pos_of_minus, 1 /*num chars to replace*/, + 1 /*num times to repeat char*/, '<'); + pos_of_minus = ourformat.find_first_of('-'); + while (pos_of_minus != std::string::npos) { + ourformat.erase(pos_of_minus, 1); + pos_of_minus = ourformat.find_first_of('-'); + } + } + // Doctor it to fix mismatches between format and data Symbol& sym(*rop.opargsym(op, arg)); OSL_ASSERT(!sym.typespec().is_structure_based()); - TypeDesc simpletype(sym.typespec().simpletype()); int num_elements = simpletype.numelements(); int num_components = simpletype.aggregate; @@ -561,148 +600,203 @@ LLVMGEN(llvm_gen_print_fmt) && formatchar != 's') { ourformat[ourformat.length() - 1] = 's'; } - if (simpletype.basetype == TypeDesc::INT && formatchar != 'd' - && formatchar != 'i' && formatchar != 'o' && formatchar != 'u' - && formatchar != 'x' && formatchar != 'X') { + + //%i is not legal in fmtlib and it will be converted to a d + if (simpletype.basetype == TypeDesc::INT + && formatchar != 'd' + /* && formatchar != 'i'*/ + && formatchar != 'o' && formatchar != 'u' && formatchar != 'x' + && formatchar != 'X') { ourformat[ourformat.length() - 1] = 'd'; } + + // //fmtlib does not use a fmt specifier for unsigned ints + // if (simpletype.basetype == TypeDesc::INT && formatchar == 'u'{ + // ourformat[ourformat.length() - 1] = ''; + // } + + + //%m,%n,%v,%p, and %c are not legal in C-style printf and end up getting filtered by oslc if (simpletype.basetype == TypeDesc::FLOAT && formatchar != 'f' - && formatchar != 'g' && formatchar != 'c' && formatchar != 'e' - && formatchar != 'm' && formatchar != 'n' && formatchar != 'p' - && formatchar != 'v') { + && formatchar != 'g' /*&& formatchar != 'c'*/ && formatchar != 'e' + /*&& formatchar != 'm' && formatchar != 'n' && formatchar != 'p' */ + /*&& formatchar != 'v'*/) { ourformat[ourformat.length() - 1] = 'f'; } - + EncodedType et = EncodedType::kUstringHash; + if (simpletype.basetype == TypeDesc::INT) { + //to mimic printf behavior when a hex specifier is used we are promoting the int to uint32_t + if (formatchar == 'x' || formatchar == 'X') { + et = EncodedType::kUInt32; + } else { + et = EncodedType::kInt32; + } + } + if (simpletype.basetype == TypeDesc::FLOAT) + et = EncodedType::kFloat; - if (simpletype.basetype == TypeDesc::INT) et = EncodedType::kInt32; - if (simpletype.basetype == TypeDesc::FLOAT) et = EncodedType::kFloat; - // TODO: translate contents of ourformat to fmtspec [flags][width][.precision][length]specifier - std::string fmtspec = "{}"; + std::string myformat("{:"); + ourformat.replace(0, 1, ""); + myformat += ourformat; + myformat += "}"; // NOTE(boulos): Only for debug mode do the derivatives get printed... for (int a = 0; a < num_elements; ++a) { llvm::Value* arrind = simpletype.arraylen ? rop.ll.constant(a) : NULL; if (sym.typespec().is_closure_based()) { - s += ourformat; + s += myformat; + llvm::Value* v = rop.llvm_load_value(sym, 0, arrind, 0); - v = rop.ll.call_function("osl_closure_to_string", + v = rop.ll.call_function("osl_closure_to_ustringhash", rop.sg_void_ptr(), v); - encodedTypes.push_back(et); - argValuesSize += SizeByEncodedType[static_cast(et)]; - loadedArgValues.push_back(v); + encodedtypes.push_back(et); + arg_values_size += pvt::size_of_encoded_type(et); + loaded_arg_values.push_back(v); continue; } for (int c = 0; c < num_components; c++) { if (c != 0 || a != 0) s += " "; - s += ourformat; - - llvm::Value* loaded = rop.llvm_load_value(sym, 0, arrind, - c); - encodedTypes.push_back(et); - argValuesSize += SizeByEncodedType[static_cast(et)]; - loadedArgValues.push_back(loaded); + s += myformat; + + llvm::Value* loaded; + if (sym.typespec().is_string_based()) { + if (rop.ll.ustring_rep() + == LLVM_Util::UstringRep::hash) { + loaded = rop.llvm_load_value(sym, 0, arrind, c); + // The value loaded is already a hash, but masquarading as a const char * + // Just need to cast it to the correct type. + loaded = rop.ll.ptr_cast(loaded, + rop.ll.type_int64()); + } else { + if (sym.is_constant() + && !sym.typespec().is_array()) { + loaded = rop.llvm_load_stringhash( + sym.get_string()); + } else { + loaded = rop.llvm_load_value(sym, 0, arrind, c); + loaded = rop.ll.call_function( + "osl_gen_ustringhash_pod", loaded); + } + } + } else { + loaded = rop.llvm_load_value(sym, 0, arrind, c); + } + + encodedtypes.push_back(et); + arg_values_size += pvt::size_of_encoded_type(et); + loaded_arg_values.push_back(loaded); } } ++arg; + } else { // Everything else -- just copy the character and advance - s += *format++; + char current_char = *format++; + s += current_char; + if (current_char == '{' || current_char == '}') { + // fmtlib expects { to be {{ + // and } to be }} + // so just duplicate the character + s += current_char; + } } } - - // Some ops prepend things if (op.opname() == op_error || op.opname() == op_warning) { s = fmtformat("Shader {} [{}]: {}", op.opname(), rop.inst()->shadername(), s); } - - // Add remainig rs_*fmt call arguments - ustring s_ustring (s.c_str()); - call_args.push_back(rop.llvm_load_stringhash(s_ustring)); //arg1: fmt_specification - //call_args.push_back(rop.ll.constant64(10)); - OSL_ASSERT(encodedTypes.size() == loadedArgValues.size()); - int arg_count = static_cast(encodedTypes.size()); - call_args.push_back(rop.ll.constant(arg_count)); //arg2: int32_t arg count - - llvm::Value* encodedTypes_on_stack = rop.ll.op_alloca(rop.ll.type_int8(), arg_count, - std::string("encodedTypes")); - llvm::Value* loadedArgValues_on_stack = rop.ll.op_alloca(rop.ll.type_int8(), argValuesSize, + ustring s_ustring(s.c_str()); + call_args.push_back(rop.llvm_load_stringhash(s_ustring)); + + OSL_ASSERT(encodedtypes.size() == loaded_arg_values.size()); + int arg_count = static_cast(encodedtypes.size()); + call_args.push_back(rop.ll.constant(arg_count)); + + llvm::Value* encodedtypes_on_stack + = rop.ll.op_alloca(rop.ll.type_int8(), arg_count, + std::string("encodedtypes")); + llvm::Value* loaded_arg_values_on_stack + = rop.ll.op_alloca(rop.ll.type_int8(), arg_values_size, std::string("argValues")); - for(int argindex=0; argindex < arg_count; ++argindex) { - - EncodedType et = encodedTypes[argindex]; - rop.ll.op_store(rop.ll.constant8(static_cast(et)), rop.ll.GEP(rop.ll.type_int8(),encodedTypes_on_stack, argindex)); - - llvm::Value* loadedArgValue = loadedArgValues[argindex]; - - llvm::Type* type = nullptr; - switch(et) { - case EncodedType::kUstringHash:{ - type = rop.ll.type_int64() ; - } - break; - case EncodedType::kInt32: { - type = rop.ll.type_int(); - } - break; - - case EncodedType::kFloat: { - type = rop.ll.type_float(); - } + int bytesToArg = 0; + for (int argindex = 0; argindex < arg_count; ++argindex) { + EncodedType et = encodedtypes[argindex]; + rop.ll.op_store(rop.ll.constant8(static_cast(et)), + rop.ll.GEP(rop.ll.type_int8(), encodedtypes_on_stack, + argindex)); + + llvm::Value* loadedArgValue = loaded_arg_values[argindex]; + + llvm::Type* type_ptr = nullptr; + switch (et) { + case EncodedType::kUstringHash: { + type_ptr = rop.ll.type_ptr(rop.ll.type_int64()); + + } break; + case EncodedType::kUInt32: + // fallthrough + case EncodedType::kInt32: { + type_ptr = rop.ll.type_int_ptr(); + } break; + + case EncodedType::kFloat: { + type_ptr = rop.ll.type_float_ptr(); + + } break; + default: + // Although more encoded types exist, the 3 above are the only + // ones we expect to be produced by OSL language itself. + OSL_ASSERT(0 && "Unhandled EncodeType"); break; + } - - - - } - rop.ll.op_store(loadedArgValue, rop.ll.GEP(type /*,rop.ll.type_int8()*/,loadedArgValues_on_stack, argindex)); + rop.ll.op_store(loadedArgValue, + rop.ll.ptr_cast(rop.ll.GEP(rop.ll.type_int8(), + loaded_arg_values_on_stack, + bytesToArg), + type_ptr)); + bytesToArg += pvt::size_of_encoded_type(et); } - - call_args.push_back(encodedTypes_on_stack); //arg3: argTypes - call_args.push_back(rop.ll.constant(argValuesSize)); //arg4: - call_args.push_back(loadedArgValues_on_stack); //argValues - + call_args.push_back(rop.ll.void_ptr(encodedtypes_on_stack)); + call_args.push_back(rop.ll.constant(arg_values_size)); + call_args.push_back(rop.ll.void_ptr(loaded_arg_values_on_stack)); // Construct the function name and call it. - const char * rs_func_name = nullptr; + const char* rs_func_name = nullptr; + if (op.opname() == op_printf) rs_func_name = "osl_gen_printfmt"; if (op.opname() == op_error) - rs_func_name = "osl_gen_errorfmt";//"rs_errorfmt_dummy"; + rs_func_name = "osl_gen_errorfmt"; if (op.opname() == op_warning) rs_func_name = "osl_gen_warningfmt"; if (op.opname() == op_fprintf) rs_func_name = "osl_gen_filefmt"; - std::cout<<"RS Function Name: "<ops()[opnum]); - - // Prepare the args for the call - if ((op.opname() == "format" || rop.use_optix())) //{} + if ((op.opname() == "format" + || rop.use_optix() )) return llvm_gen_printf_legacy(rop, opnum); else return llvm_gen_print_fmt(rop, opnum); } - - LLVMGEN(llvm_gen_add) { Opcode& op(rop.inst()->ops()[opnum]); @@ -1400,17 +1494,18 @@ LLVMGEN(llvm_gen_compref) if (rop.inst()->master()->range_checking()) { if (!(Index.is_constant() && Index.get_int() >= 0 && Index.get_int() < 3)) { - llvm::Value* args[] = { c, - rop.ll.constant(3), - rop.ll.constant(Val.unmangled()), - rop.sg_void_ptr(), - rop.ll.constant(op.sourcefile()), - rop.ll.constant(op.sourceline()), - rop.ll.constant(rop.group().name()), - rop.ll.constant(rop.layer()), - rop.ll.constant(rop.inst()->layername()), - rop.ll.constant(rop.inst()->shadername()) }; - c = rop.ll.call_function("osl_range_check", args); + llvm::Value* args[] + = { c, + rop.ll.constant(3), + rop.llvm_load_stringhash(Val.unmangled()), + rop.sg_void_ptr(), + rop.llvm_load_stringhash(op.sourcefile()), + rop.ll.constant(op.sourceline()), + rop.llvm_load_stringhash(rop.group().name()), + rop.ll.constant(rop.layer()), + rop.llvm_load_stringhash(rop.inst()->layername()), + rop.llvm_load_stringhash(rop.inst()->shadername()) }; + c = rop.ll.call_function("osl_range_check", args); } } @@ -1444,17 +1539,18 @@ LLVMGEN(llvm_gen_compassign) if (rop.inst()->master()->range_checking()) { if (!(Index.is_constant() && Index.get_int() >= 0 && Index.get_int() < 3)) { - llvm::Value* args[] = { c, - rop.ll.constant(3), - rop.ll.constant(Result.unmangled()), - rop.sg_void_ptr(), - rop.ll.constant(op.sourcefile()), - rop.ll.constant(op.sourceline()), - rop.ll.constant(rop.group().name()), - rop.ll.constant(rop.layer()), - rop.ll.constant(rop.inst()->layername()), - rop.ll.constant(rop.inst()->shadername()) }; - c = rop.ll.call_function("osl_range_check", args); + llvm::Value* args[] + = { c, + rop.ll.constant(3), + rop.llvm_load_stringhash(Result.unmangled()), + rop.sg_void_ptr(), + rop.llvm_load_stringhash(op.sourcefile()), + rop.ll.constant(op.sourceline()), + rop.llvm_load_stringhash(rop.group().name()), + rop.ll.constant(rop.layer()), + rop.llvm_load_stringhash(rop.inst()->layername()), + rop.llvm_load_stringhash(rop.inst()->shadername()) }; + c = rop.ll.call_function("osl_range_check", args); } } @@ -1490,16 +1586,17 @@ LLVMGEN(llvm_gen_mxcompref) if (!(Row.is_constant() && Col.is_constant() && Row.get_int() >= 0 && Row.get_int() < 4 && Col.get_int() >= 0 && Col.get_int() < 4)) { - llvm::Value* args[] = { row, - rop.ll.constant(4), - rop.ll.constant(M.name()), - rop.sg_void_ptr(), - rop.ll.constant(op.sourcefile()), - rop.ll.constant(op.sourceline()), - rop.ll.constant(rop.group().name()), - rop.ll.constant(rop.layer()), - rop.ll.constant(rop.inst()->layername()), - rop.ll.constant(rop.inst()->shadername()) }; + llvm::Value* args[] + = { row, + rop.ll.constant(4), + rop.llvm_load_stringhash(M.name()), + rop.sg_void_ptr(), + rop.llvm_load_stringhash(op.sourcefile()), + rop.ll.constant(op.sourceline()), + rop.llvm_load_stringhash(rop.group().name()), + rop.ll.constant(rop.layer()), + rop.llvm_load_stringhash(rop.inst()->layername()), + rop.llvm_load_stringhash(rop.inst()->shadername()) }; if (!(Row.is_constant() && Row.get_int() >= 0 && Row.get_int() < 4)) { row = rop.ll.call_function("osl_range_check", args); @@ -1546,16 +1643,17 @@ LLVMGEN(llvm_gen_mxcompassign) if (!(Row.is_constant() && Col.is_constant() && Row.get_int() >= 0 && Row.get_int() < 4 && Col.get_int() >= 0 && Col.get_int() < 4)) { - llvm::Value* args[] = { row, - rop.ll.constant(4), - rop.ll.constant(Result.name()), - rop.sg_void_ptr(), - rop.ll.constant(op.sourcefile()), - rop.ll.constant(op.sourceline()), - rop.ll.constant(rop.group().name()), - rop.ll.constant(rop.layer()), - rop.ll.constant(rop.inst()->layername()), - rop.ll.constant(rop.inst()->shadername()) }; + llvm::Value* args[] + = { row, + rop.ll.constant(4), + rop.llvm_load_stringhash(Result.name()), + rop.sg_void_ptr(), + rop.llvm_load_stringhash(op.sourcefile()), + rop.ll.constant(op.sourceline()), + rop.llvm_load_stringhash(rop.group().name()), + rop.ll.constant(rop.layer()), + rop.llvm_load_stringhash(rop.inst()->layername()), + rop.llvm_load_stringhash(rop.inst()->shadername()) }; if (!(Row.is_constant() && Row.get_int() >= 0 && Row.get_int() < 4)) { row = rop.ll.call_function("osl_range_check", args); @@ -1619,14 +1717,14 @@ LLVMGEN(llvm_gen_aref) llvm::Value* args[] = { index, rop.ll.constant(Src.typespec().arraylength()), - rop.ll.constant(Src.unmangled()), + rop.llvm_load_stringhash(Src.unmangled()), rop.sg_void_ptr(), - rop.ll.constant(op.sourcefile()), + rop.llvm_load_stringhash(op.sourcefile()), rop.ll.constant(op.sourceline()), - rop.ll.constant(rop.group().name()), + rop.llvm_load_stringhash(rop.group().name()), rop.ll.constant(rop.layer()), - rop.ll.constant(rop.inst()->layername()), - rop.ll.constant(rop.inst()->shadername()) }; + rop.llvm_load_stringhash(rop.inst()->layername()), + rop.llvm_load_stringhash(rop.inst()->shadername()) }; index = rop.ll.call_function("osl_range_check", args); } } @@ -1664,14 +1762,14 @@ LLVMGEN(llvm_gen_aassign) llvm::Value* args[] = { index, rop.ll.constant(Result.typespec().arraylength()), - rop.ll.constant(Result.unmangled()), + rop.llvm_load_stringhash(Result.unmangled()), rop.sg_void_ptr(), - rop.ll.constant(op.sourcefile()), + rop.llvm_load_stringhash(op.sourcefile()), rop.ll.constant(op.sourceline()), - rop.ll.constant(rop.group().name()), + rop.llvm_load_stringhash(rop.group().name()), rop.ll.constant(rop.layer()), - rop.ll.constant(rop.inst()->layername()), - rop.ll.constant(rop.inst()->shadername()) }; + rop.llvm_load_stringhash(rop.inst()->layername()), + rop.llvm_load_stringhash(rop.inst()->shadername()) }; index = rop.ll.call_function("osl_range_check", args); } } diff --git a/src/liboslexec/llvm_instance.cpp b/src/liboslexec/llvm_instance.cpp index 12f6299087..73b634dc09 100644 --- a/src/liboslexec/llvm_instance.cpp +++ b/src/liboslexec/llvm_instance.cpp @@ -247,24 +247,24 @@ BackendLLVM::llvm_type_sg() sg_types.push_back(triple_deriv); // Ps llvm::Type* vp = (llvm::Type*)ll.type_void_ptr(); - sg_types.push_back(vp); // opaque renderstate* - sg_types.push_back(vp); // opaque tracedata* - sg_types.push_back(vp); // opaque objdata* - sg_types.push_back(vp); // ShadingContext* - sg_types.push_back(vp); // OpaqueShadingStateUniformPtr - sg_types.push_back(ll.type_int()); //shade_index - sg_types.push_back(ll.type_int()); //thread_index - sg_types.push_back(vp); // RendererServices* - sg_types.push_back(vp); // object2common - sg_types.push_back(vp); // shader2common - sg_types.push_back(vp); // Ci + sg_types.push_back(vp); // opaque renderstate* + sg_types.push_back(vp); // opaque tracedata* + sg_types.push_back(vp); // opaque objdata* + sg_types.push_back(vp); // ShadingContext* + sg_types.push_back(vp); // OpaqueShadingStateUniformPtr + sg_types.push_back(ll.type_int()); //thread_index + sg_types.push_back(ll.type_int()); //shade_index + sg_types.push_back(vp); // RendererServices* + sg_types.push_back(vp); // object2common + sg_types.push_back(vp); // shader2common + sg_types.push_back(vp); // Ci sg_types.push_back(ll.type_float()); // surfacearea sg_types.push_back(ll.type_int()); // raytype sg_types.push_back(ll.type_int()); // flipHandedness sg_types.push_back(ll.type_int()); // backfacing - return m_llvm_type_sg = ll.type_struct(sg_types, "struct.OSL_v1_13_2::ShaderGlobals"); + return m_llvm_type_sg = ll.type_struct(sg_types, "ShaderGlobals"); } @@ -431,7 +431,8 @@ BackendLLVM::llvm_type_closure_component_ptr() return ll.type_ptr(llvm_type_closure_component()); } -void BackendLLVM::build_offsets_of_ShaderGlobals( +void +BackendLLVM::build_offsets_of_ShaderGlobals( std::vector& offset_by_index) { typedef OSL::ShaderGlobals sgBatch; @@ -459,8 +460,8 @@ void BackendLLVM::build_offsets_of_ShaderGlobals( offset_by_index.push_back(offsetof(ShaderGlobals, context)); offset_by_index.push_back(offsetof(ShaderGlobals, shadingStateUniform)); - offset_by_index.push_back(offsetof(ShaderGlobals, shade_index)); offset_by_index.push_back(offsetof(ShaderGlobals, thread_index)); + offset_by_index.push_back(offsetof(ShaderGlobals, shade_index)); offset_by_index.push_back(offsetof(ShaderGlobals, renderer)); @@ -472,12 +473,7 @@ void BackendLLVM::build_offsets_of_ShaderGlobals( offset_by_index.push_back(offsetof(ShaderGlobals, raytype)); offset_by_index.push_back(offsetof(ShaderGlobals, flipHandedness)); offset_by_index.push_back(offsetof(ShaderGlobals, backfacing)); - - - } - - void BackendLLVM::llvm_assign_initial_value(const Symbol& sym, bool force) { @@ -610,12 +606,12 @@ BackendLLVM::llvm_assign_initial_value(const Symbol& sym, bool force) llvm_void_ptr(sym), ll.constant((int)sym.has_derivs()), sg_void_ptr(), - llvm_load_string(inst()->shadername()), + llvm_load_stringhash(inst()->shadername()), ll.constant(0), - llvm_load_string(sym.unmangled()), + llvm_load_stringhash(sym.unmangled()), ll.constant(0), ll.constant(ncomps), - llvm_load_string("") }; + llvm_load_stringhash("") }; ll.call_function("osl_naninf_check", args); } // userdata pre-placement always succeeds, we don't need to bother @@ -753,16 +749,13 @@ BackendLLVM::llvm_generate_debugnan(const Opcode& op) ncheck = ll.constant(1); } - llvm::Value* args[] = { ncomps, - llvm_void_ptr(sym), - ll.constant((int)sym.has_derivs()), - sg_void_ptr(), - ll.constant(op.sourcefile()), - ll.constant(op.sourceline()), - ll.constant(sym.unmangled()), - offset, - ncheck, - ll.constant(op.opname()) }; + llvm::Value* args[] = { + ncomps, llvm_void_ptr(sym), ll.constant((int)sym.has_derivs()), + sg_void_ptr(), + llvm_load_stringhash(op.sourcefile()), ll.constant(op.sourceline()), + llvm_load_stringhash(sym.unmangled()), offset, ncheck, + llvm_load_stringhash(op.opname()) + }; ll.call_function("osl_naninf_check", args); } } @@ -861,16 +854,16 @@ BackendLLVM::llvm_generate_debug_uninit(const Opcode& op) llvm::Value* args[] = { ll.constant(t), llvm_void_ptr(sym), sg_void_ptr(), - ll.constant(op.sourcefile()), + llvm_load_stringhash(op.sourcefile()), ll.constant(op.sourceline()), - ll.constant(group().name()), + llvm_load_stringhash(group().name()), ll.constant(layer()), - ll.constant(inst()->layername()), - ll.constant(inst()->shadername().c_str()), + llvm_load_stringhash(inst()->layername()), + llvm_load_stringhash(inst()->shadername()), ll.constant(int(&op - &inst()->ops()[0])), - ll.constant(op.opname()), + llvm_load_stringhash(op.opname()), ll.constant(i), - ll.constant(sym.unmangled()), + llvm_load_stringhash(sym.unmangled()), offset, ncheck }; ll.call_function("osl_uninit_check", args); @@ -1309,12 +1302,12 @@ BackendLLVM::build_llvm_instance(bool groupentry) llvm_void_ptr(s), ll.constant((int)s.has_derivs()), sg_void_ptr(), - ll.constant(ustring(inst()->shadername())), + llvm_load_stringhash(inst()->shadername()), ll.constant(0), - ll.constant(s.unmangled()), + llvm_load_stringhash(s.unmangled()), ll.constant(0), ll.constant(ncomps), - ll.constant("") }; + llvm_load_stringhash("") }; ll.call_function("osl_naninf_check", args); } } @@ -1598,9 +1591,6 @@ empty_group_func(void*, void*) void BackendLLVM::run() { - - - if (group().does_nothing()) { group().llvm_compiled_init((RunLLVMGroupFunc)empty_group_func); group().llvm_compiled_version((RunLLVMGroupFunc)empty_group_func); @@ -1650,9 +1640,12 @@ BackendLLVM::run() "llvm::parseBitcodeFile returned '{}' for llvm_rs_dependent_ops\n", err); - // std::vector offset_by_index; - // build_offsets_of_ShaderGlobals(offset_by_index); - // ll.validate_struct_data_layout(m_llvm_type_sg, offset_by_index); +//Leaving this around for developers to make sure LLVM's shaderglobals and C++'s are binary compatible +# if 0 + std::vector offset_by_index; + build_offsets_of_ShaderGlobals(offset_by_index); + ll.validate_struct_data_layout(m_llvm_type_sg, offset_by_index); +# endif std::vector& rs_free_function_bitcode = shadingsys().m_rs_bitcode; @@ -1773,18 +1766,6 @@ BackendLLVM::run() group().name(), m_llvm_local_mem / 1024); } - //const char *prune_filename_ir = "MOD.B4.PRUNE.ll"; - - - std::ofstream prune_bir("MOD.B4.PRUNE.ll"); - prune_bir<= 2 || shadingsys().llvm_output_bitcode()) { // Make a safe group name that doesn't have "/" in it! Also beware @@ -1855,7 +1831,7 @@ BackendLLVM::run() ll.validate_global_mappings(names_of_unmapped_globals); if (!names_of_unmapped_globals.empty()) { shadingsys().errorfmt( - "Renderers should call osl::register_JIT_Global(const char* global_var_name, void* global_var_addr) for each global variable used by its free function renderer services bitcode"); + "Renderers should call OSL::register_JIT_Global(const char* global_var_name, void* global_var_addr) for each global variable used by its free function renderer services bitcode"); for (const auto& unmapped_name : names_of_unmapped_globals) { shadingsys().errorfmt( ">>>>External global variable {} was not mapped to an address!", diff --git a/src/liboslexec/llvm_ops.cpp b/src/liboslexec/llvm_ops.cpp index 888c590465..80f3ba48c0 100644 --- a/src/liboslexec/llvm_ops.cpp +++ b/src/liboslexec/llvm_ops.cpp @@ -59,9 +59,10 @@ examples), as you are just coding in C++, but there are some rules: OSL_SHADEOP, since they don't need to be runtime-discoverable by LLVM. * If you need to access non-passed globals (P, N, etc.) or make renderer - callbacks, just make the first argument to the function a void* that - you cast to a ShaderGlobals* and access the globals, shading - context (sg->context), opaque renderer state (sg->renderstate), etc. + callbacks, just make the first argument to the function is an + OpaqueExecContextPtr (void* ec) that is passed to get_*() functions to + the globals get_P(ec), get_N(ec), typed renderer state + get_rs(ec), etc. */ @@ -930,10 +931,9 @@ calculatenormal(void* P_, bool flipHandedness) } OSL_SHADEOP void -osl_calculatenormal(void* out, void* sg_, void* P_) +osl_calculatenormal(void* out, OpaqueExecContextPtr ec, void* P_) { - ShaderGlobals* sg = (ShaderGlobals*)sg_; - Vec3 N = calculatenormal(P_, sg->flipHandedness); + Vec3 N = calculatenormal(P_, OSL::get_flipHandedness(ec)); // Don't normalize N VEC(out) = N; } @@ -974,30 +974,30 @@ osl_filterwidth_vdv(void* out, void* x_) // Asked if the raytype includes a bit pattern. OSL_SHADEOP int -osl_raytype_bit(void* sg_, int bit) +osl_raytype_bit(OpaqueExecContextPtr ec, int bit) { - ShaderGlobals* sg = (ShaderGlobals*)sg_; - return (sg->raytype & bit) != 0; + return (OSL::get_raytype(ec) & bit) != 0; } // extern declaration OSL_SHADEOP_NOINLINE int -osl_range_check_err(int indexvalue, int length, ustring_pod symname, void* sg, - ustring_pod sourcefile, int sourceline, - ustring_pod groupname, int layer, ustring_pod layername, - ustring_pod shadername); +osl_range_check_err(int indexvalue, int length, ustringhash_pod symname, + OpaqueExecContextPtr ec, ustringhash_pod sourcefile, + int sourceline, ustringhash_pod groupname, int layer, + ustringhash_pod layername, ustringhash_pod shadername); OSL_SHADEOP int -osl_range_check(int indexvalue, int length, ustring_pod symname, void* sg, - ustring_pod sourcefile, int sourceline, ustring_pod groupname, - int layer, ustring_pod layername, ustring_pod shadername) +osl_range_check(int indexvalue, int length, ustringhash_pod symname, + OpaqueExecContextPtr ec, ustringhash_pod sourcefile, + int sourceline, ustringhash_pod groupname, int layer, + ustringhash_pod layername, ustringhash_pod shadername) { if (indexvalue < 0 || indexvalue >= length) { - indexvalue = osl_range_check_err(indexvalue, length, symname, sg, + indexvalue = osl_range_check_err(indexvalue, length, symname, ec, sourcefile, sourceline, groupname, layer, layername, shadername); } diff --git a/src/liboslexec/llvm_util.cpp b/src/liboslexec/llvm_util.cpp index 07825f40db..f4dafc30c2 100644 --- a/src/liboslexec/llvm_util.cpp +++ b/src/liboslexec/llvm_util.cpp @@ -435,6 +435,8 @@ LLVM_Util::LLVM_Util(const PerThreadInfo& per_thread_info, int debuglevel, *m_llvm_context); m_llvm_type_int8_ptr = (llvm::PointerType*)llvm::Type::getInt8PtrTy( *m_llvm_context); + m_llvm_type_int64_ptr = (llvm::PointerType*)llvm::Type::getInt64PtrTy( + *m_llvm_context); m_llvm_type_bool = (llvm::Type*)llvm::Type::getInt1Ty(*m_llvm_context); m_llvm_type_bool_ptr = (llvm::PointerType*)llvm::Type::getInt1PtrTy( *m_llvm_context); @@ -3626,7 +3628,6 @@ LLVM_Util::call_function(llvm::Value* func, cspan args) OSL_GCC_PRAGMA(GCC diagnostic ignored "-Wdeprecated-declarations") // FIXME: This will need to be revisited for future LLVM 16+ that fully // drops typed pointers. - std::cout<<"Args data: "<(func->getType()->getPointerElementType()), func, llvm::ArrayRef(args.data(), args.size())); @@ -5206,6 +5207,15 @@ LLVM_Util::op_masked_return() void LLVM_Util::op_store(llvm::Value* val, llvm::Value* ptr) { + // Something bad might happen, and we think it is worth leaving checks + if (ptr->getType() != type_ptr(val->getType())) { + std::cerr << "We have a type mismatch! op_store ptr->getType()=" <getType()->print(llvm::errs()); + std::cerr << std::endl; + std::cerr << "op_store val->getType()="<getType()->print(llvm::errs()); + std::cerr << std::endl; + } if (m_mask_stack.empty() || val->getType()->isVectorTy() == false || (!is_masking_required())) { //OSL_DEV_ONLY(std::cout << "unmasked op_store" << std::endl); We diff --git a/src/liboslexec/opclosure.cpp b/src/liboslexec/opclosure.cpp index 53c3e0fbab..fdca5fa4c8 100644 --- a/src/liboslexec/opclosure.cpp +++ b/src/liboslexec/opclosure.cpp @@ -69,6 +69,7 @@ osl_allocate_weighted_closure_component(ShaderGlobals* sg, int id, int size, return sg->context->closure_component_allot(id, size, *w); } +// Deprecated, remove when conversion from ustring to ustringhash is finished OSL_SHADEOP const char* osl_closure_to_string(ShaderGlobals* sg, ClosureColor* c) { @@ -79,6 +80,17 @@ osl_closure_to_string(ShaderGlobals* sg, ClosureColor* c) return ustring(stream.str()).c_str(); } +OSL_SHADEOP ustringhash_pod +osl_closure_to_ustringhash(ShaderGlobals* sg, ClosureColor* c) +{ + // Special case for printing closures + std::ostringstream stream; + stream.imbue(std::locale::classic()); // force C locale + print_closure(stream, c, &sg->context->shadingsys()); + return ustring(stream.str()).hash(); +} + + } // namespace pvt OSL_NAMESPACE_EXIT diff --git a/src/liboslexec/opcolor.cpp b/src/liboslexec/opcolor.cpp index 096511fac4..08a4357bdb 100644 --- a/src/liboslexec/opcolor.cpp +++ b/src/liboslexec/opcolor.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include @@ -223,24 +223,18 @@ ColorSystem::set_colorspace(StringParam colorspace) extern "C" __device__ void osl_printf(void* sg_, char* fmt_str, void* args); -extern "C" __device__ int -rend_get_userdata(StringParam name, void* data, int data_size, - const OSL::TypeDesc& type, int index); + extern "C" __device__ int + rend_get_userdata(StringParam name, void* data, int data_size, + const OSL::TypeDesc& type, int index); OSL_HOSTDEVICE void -ColorSystem::error(StringParam src, StringParam dst, Context sg) const +ColorSystem::error(StringParam src, StringParam dst, ExecContextPtr ec) const { -# ifndef __CUDA_ARCH__ - const char* args[2] = { src.c_str(), dst.c_str() }; - osl_printf(sg, - (char*) // FIXME! - "ERROR: Unknown color space transformation \"%s\" -> \"%s\"\n", - args); -# endif +// Unsupported currently } __device__ static inline const ColorSystem& -op_color_colorsystem(void* sg) +get_colorsystem(OSL::OpaqueExecContextPtr oec) { void* ptr; rend_get_userdata(STRING_PARAMS(colorsystem), &ptr, 8, OSL::TypeDesc::PTR, @@ -248,48 +242,32 @@ op_color_colorsystem(void* sg) return *((ColorSystem*)ptr); } -__device__ static inline void* -op_color_context(void* sg) -{ - return sg; -} - #else - void -ColorSystem::error(StringParam src, StringParam dst, Context ctx) const +ColorSystem::error(StringParam src, StringParam dst, ExecContextPtr ec) const { -#if defined(__OSL_WIDTH) // batched version - context->errorfmt("Unknown color space transformation \"{}\" -> \"{}\"", - src, dst); -#else - ShaderGlobals *sg = ctx; // ctx should already be a ShaderGlobals, but improve readability - osl_printfmt(sg, ustringhash("Unknown color space transformation \"{}\" -> \"{}\""), +# if defined(__OSL_WIDTH) // batched version + // Batched isn't using the new error reporting interface, + // so continue to go through CPU only ShadingContext + ec->context->errorfmt("Unknown color space transformation \"{}\" -> \"{}\"", + src, dst); +# else + OSL::errorfmt(ec, + "Unknown color space transformation \"{}\" -> \"{}\"", src, dst); -#endif +# endif } -static inline const ColorSystem& -op_color_colorsystem(void* sg_) -{ - ShaderGlobals* sg = (ShaderGlobals*)sg_; - ShadingStateUniform* ssu = (ShadingStateUniform*)sg->shadingStateUniform; - return ssu->m_colorsystem; -} +namespace { -#if defined(__OSL_WIDTH) // batched version -static inline OSL::ShadingContext* -op_color_context(void* sg) +inline const ColorSystem& +get_colorsystem(OSL::OpaqueExecContextPtr oec) { - return (ShadingContext*)((ShaderGlobals*)sg)->context; -} -#else -static inline ShaderGlobals* -op_color_context(/*ShaderGlobals**/void* sg) -{ - return (ShaderGlobals*)sg; + auto ec = pvt::get_ec(oec); + ShadingStateUniform* ssu = (ShadingStateUniform*)ec->shadingStateUniform; + return ssu->m_colorsystem; } -#endif +} // namespace #endif @@ -297,22 +275,15 @@ op_color_context(/*ShaderGlobals**/void* sg) template OSL_HOSTDEVICE Color ColorSystem::ocio_transform(StringParam fromspace, StringParam tospace, - const Color& C, Context ctx) const + const Color& C, ExecContextPtr ec) const { #ifndef __CUDA_ARCH__ - #if defined(__OSL_WIDTH) // batched version Color Cout; - if (ctx->ocio_transform(fromspace, tospace, C, Cout))//SM: Can this not be part of ShadingContext? + // Currently CPU only supports ocio by going through ShadingContext + if (ec->context->ocio_transform(fromspace, tospace, C, Cout)) return Cout; - #else - error(fromspace, tospace, ctx); - return C; - #endif - - #endif - - error(fromspace, tospace, ctx); + error(fromspace, tospace, ec); return C; } @@ -320,25 +291,25 @@ ColorSystem::ocio_transform(StringParam fromspace, StringParam tospace, OSL_HOSTDEVICE Dual2 ColorSystem::ocio_transform(StringParam fromspace, StringParam tospace, - const Dual2& C, Context ctx) const + const Dual2& C, ExecContextPtr ec) const { - return ocio_transform>(fromspace, tospace, C, ctx); + return ocio_transform>(fromspace, tospace, C, ec); } OSL_HOSTDEVICE Color3 ColorSystem::ocio_transform(StringParam fromspace, StringParam tospace, - const Color3& C, Context ctx) const + const Color3& C, ExecContextPtr ec) const { - return ocio_transform(fromspace, tospace, C, ctx); + return ocio_transform(fromspace, tospace, C, ec); } OSL_HOSTDEVICE Color3 ColorSystem::to_rgb(StringParam fromspace, const Color3& C, - Context context) const + ExecContextPtr ec) const { // NOTE: any changes here should be mirrored // in wide_prepend_color_from in wide_opcolor.cpp @@ -356,14 +327,14 @@ ColorSystem::to_rgb(StringParam fromspace, const Color3& C, if (fromspace == STRING_PARAMS(xyY)) return XYZ_to_RGB(xyY_to_XYZ(C)); else - return ocio_transform(fromspace, STRING_PARAMS(RGB), C, context); + return ocio_transform(fromspace, STRING_PARAMS(RGB), C, ec); } OSL_HOSTDEVICE Color3 ColorSystem::from_rgb(StringParam tospace, const Color3& C, - Context context) const + ExecContextPtr ec) const { if (tospace == STRING_PARAMS(RGB) || tospace == STRING_PARAMS(rgb) || tospace == m_colorspace) @@ -379,7 +350,7 @@ ColorSystem::from_rgb(StringParam tospace, const Color3& C, if (tospace == STRING_PARAMS(xyY)) return XYZ_to_xyY(RGB_to_XYZ(C)); else - return ocio_transform(STRING_PARAMS(RGB), tospace, C, context); + return ocio_transform(STRING_PARAMS(RGB), tospace, C, ec); } @@ -387,7 +358,7 @@ ColorSystem::from_rgb(StringParam tospace, const Color3& C, template OSL_HOSTDEVICE COLOR ColorSystem::transformc(StringParam fromspace, StringParam tospace, - const COLOR& C, Context context) const + const COLOR& C, ExecContextPtr ec) const { // NOTE: any changes here should be mirrored // in wide_transformc in wide_opcolor.cpp @@ -435,7 +406,7 @@ ColorSystem::transformc(StringParam fromspace, StringParam tospace, } if (use_colorconfig) { - Cto = ocio_transform(fromspace, tospace, C, context); + Cto = ocio_transform(fromspace, tospace, C, ec); } return Cto; @@ -445,18 +416,18 @@ ColorSystem::transformc(StringParam fromspace, StringParam tospace, OSL_HOSTDEVICE Dual2 ColorSystem::transformc(StringParam fromspace, StringParam tospace, - const Dual2& color, Context ctx) const + const Dual2& color, ExecContextPtr ec) const { - return transformc>(fromspace, tospace, color, ctx); + return transformc>(fromspace, tospace, color, ec); } OSL_HOSTDEVICE Color3 ColorSystem::transformc(StringParam fromspace, StringParam tospace, - const Color3& color, Context ctx) const + const Color3& color, ExecContextPtr ec) const { - return transformc(fromspace, tospace, color, ctx); + return transformc(fromspace, tospace, color, ec); } } // namespace pvt @@ -464,18 +435,18 @@ ColorSystem::transformc(StringParam fromspace, StringParam tospace, OSL_SHADEOP OSL_HOSTDEVICE void -osl_blackbody_vf(void* sg, void* out, float temp) +osl_blackbody_vf(OpaqueExecContextPtr oec, void* out, float temp) { - const ColorSystem& cs = op_color_colorsystem(sg); + const ColorSystem& cs = get_colorsystem(oec); *(Color3*)out = cs.blackbody_rgb(temp); } OSL_SHADEOP OSL_HOSTDEVICE void -osl_wavelength_color_vf(void* sg, void* out, float lambda) +osl_wavelength_color_vf(OpaqueExecContextPtr oec, void* out, float lambda) { - const ColorSystem& cs = op_color_colorsystem(sg); + const ColorSystem& cs = get_colorsystem(oec); Color3 rgb = cs.XYZ_to_RGB(wavelength_color_XYZ(lambda)); // constrain_rgb (rgb); rgb *= 1.0 / 2.52; // Empirical scale from lg to make all comps <= 1 @@ -487,18 +458,18 @@ osl_wavelength_color_vf(void* sg, void* out, float lambda) OSL_SHADEOP OSL_HOSTDEVICE void -osl_luminance_fv(void* sg, void* out, void* c) +osl_luminance_fv(OpaqueExecContextPtr oec, void* out, void* c) { - const ColorSystem& cs = op_color_colorsystem(sg); + const ColorSystem& cs = get_colorsystem(oec); ((float*)out)[0] = cs.luminance(((const Color3*)c)[0]); } OSL_SHADEOP OSL_HOSTDEVICE void -osl_luminance_dfdv(void* sg, void* out, void* c) +osl_luminance_dfdv(OpaqueExecContextPtr oec, void* out, void* c) { - const ColorSystem& cs = op_color_colorsystem(sg); + const ColorSystem& cs = get_colorsystem(oec); ((float*)out)[0] = cs.luminance(((const Color3*)c)[0]); ((float*)out)[1] = cs.luminance(((const Color3*)c)[1]); ((float*)out)[2] = cs.luminance(((const Color3*)c)[2]); @@ -507,26 +478,25 @@ osl_luminance_dfdv(void* sg, void* out, void* c) OSL_SHADEOP OSL_HOSTDEVICE void -osl_prepend_color_from(void* sg, void* c_, const char* from) +osl_prepend_color_from(OpaqueExecContextPtr oec, void* c_, const char* from) { - const ColorSystem& cs = op_color_colorsystem(sg); - COL(c_) = cs.to_rgb(HDSTR(from), COL(c_), op_color_context(sg)); + const ColorSystem& cs = get_colorsystem(oec); + COL(c_) = cs.to_rgb(HDSTR(from), COL(c_), pvt::get_ec(oec)); } OSL_SHADEOP OSL_HOSTDEVICE int -osl_transformc(void* sg, void* Cin, int Cin_derivs, void* Cout, int Cout_derivs, - void* from_, void* to_) +osl_transformc(OpaqueExecContextPtr oec, void* Cin, int Cin_derivs, void* Cout, + int Cout_derivs, void* from_, void* to_) { - const ColorSystem& cs = op_color_colorsystem(sg); + const ColorSystem& cs = get_colorsystem(oec); StringParam from = HDSTR(from_); StringParam to = HDSTR(to_); if (Cout_derivs) { if (Cin_derivs) { - DCOL(Cout) = cs.transformc(from, to, DCOL(Cin), - op_color_context(sg)); + DCOL(Cout) = cs.transformc(from, to, DCOL(Cin), pvt::get_ec(oec)); return true; } else { // We had output derivs, but not input. Zero the output @@ -537,7 +507,7 @@ osl_transformc(void* sg, void* Cin, int Cin_derivs, void* Cout, int Cout_derivs, } // No-derivs case - COL(Cout) = cs.transformc(from, to, COL(Cin), op_color_context(sg)); + COL(Cout) = cs.transformc(from, to, COL(Cin), pvt::get_ec(oec)); return true; } diff --git a/src/liboslexec/opcolor.h b/src/liboslexec/opcolor.h index ce6857d573..92de557d35 100644 --- a/src/liboslexec/opcolor.h +++ b/src/liboslexec/opcolor.h @@ -22,20 +22,15 @@ OSL_NAMESPACE_ENTER -class ShadingContext; +//Forward declare struct ShaderGlobals; +typedef ShaderGlobals ExecContext; +typedef ExecContext* ExecContextPtr; namespace pvt { class OSLEXECPUBLIC ColorSystem { -#ifdef __CUDACC__ - using Context = void*; -#elif defined(__OSL_WIDTH) // batched version - using Context = ShadingContext*; -#else - using Context = ShaderGlobals*; -#endif public: // A colour system is defined by the CIE x and y coordinates of its // three primary illuminants and its white point. @@ -89,27 +84,27 @@ class OSLEXECPUBLIC ColorSystem { OSL_HOSTDEVICE bool set_colorspace(StringParam colorspace); OSL_HOSTDEVICE Color3 to_rgb(StringParam fromspace, const Color3& C, - Context) const; + ExecContextPtr) const; OSL_HOSTDEVICE Color3 from_rgb(StringParam fromspace, const Color3& C, - Context) const; + ExecContextPtr) const; OSL_HOSTDEVICE Dual2 transformc(StringParam fromspace, StringParam tospace, const Dual2& color, - Context ctx) const; + ExecContextPtr) const; OSL_HOSTDEVICE Color3 transformc(StringParam fromspace, StringParam tospace, - const Color3& color, Context ctx) const; + const Color3& color, ExecContextPtr) const; OSL_HOSTDEVICE Dual2 ocio_transform(StringParam fromspace, StringParam tospace, const Dual2& C, - Context) const; + ExecContextPtr) const; OSL_HOSTDEVICE Color3 ocio_transform(StringParam fromspace, StringParam tospace, const Color3& C, - Context) const; + ExecContextPtr) const; OSL_HOSTDEVICE const StringParam& colorspace() const @@ -117,18 +112,19 @@ class OSLEXECPUBLIC ColorSystem { return m_colorspace; } - OSL_HOSTDEVICE void error(StringParam src, StringParam dst, Context) const; + OSL_HOSTDEVICE void error(StringParam src, StringParam dst, + ExecContextPtr) const; private: template OSL_HOSTDEVICE inline Color transformc(StringParam fromspace, StringParam tospace, const Color& C, - Context) const; + ExecContextPtr) const; template - OSL_HOSTDEVICE inline Color ocio_transform(StringParam fromspace, - StringParam tospace, - const Color& C, Context) const; + OSL_HOSTDEVICE inline Color + ocio_transform(StringParam fromspace, StringParam tospace, const Color& C, + ExecContextPtr) const; // Derived/cached calculations from options: diff --git a/src/liboslexec/opfmt.cpp b/src/liboslexec/opfmt.cpp new file mode 100644 index 0000000000..d0d5944a03 --- /dev/null +++ b/src/liboslexec/opfmt.cpp @@ -0,0 +1,113 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +///////////////////////////////////////////////////////////////////////// +/// \file +/// +/// Shader interpreter implementation of string functions +/// such as format, concat, printf, etc. +/// +///////////////////////////////////////////////////////////////////////// + +//#include +#include +#include + + +#include +#include + + +#include "oslexec_pvt.h" +#include "shading_state_uniform.h" + + +OSL_NAMESPACE_ENTER +namespace pvt { + + + +// Shims to convert llvm gen to rs free function C++ parameter types +// and forward on calls to re free functions. + +OSL_RSOP OSL::ustringhash_pod +osl_gen_ustringhash_pod(const char* s) +{ + return USTR(s).hash(); +} + +OSL_RSOP void +osl_gen_errorfmt(OpaqueExecContextPtr exec_ctx, + OSL::ustringhash_pod fmt_specification, int32_t arg_count, + void* arg_types, uint32_t arg_values_size, uint8_t* arg_values) +{ + OSL::ustringhash rs_fmt_specification = OSL::ustringhash_from( + fmt_specification); + auto encoded_types = reinterpret_cast(arg_types); + + rs_errorfmt(exec_ctx, rs_fmt_specification, arg_count, encoded_types, + arg_values_size, arg_values); +} + + + +OSL_RSOP void +osl_gen_warningfmt(OpaqueExecContextPtr exec_ctx, + OSL::ustringhash_pod fmt_specification, int32_t arg_count, + void* arg_types, uint32_t arg_values_size, uint8_t* arg_values) +{ + OSL::ustringhash rs_fmt_specification = OSL::ustringhash_from( + fmt_specification); + auto encoded_types = reinterpret_cast(arg_types); + + rs_warningfmt(exec_ctx, rs_fmt_specification, arg_count, encoded_types, + arg_values_size, arg_values); +} + + +OSL_RSOP void +osl_gen_printfmt(OpaqueExecContextPtr exec_ctx, + OSL::ustringhash_pod fmt_specification, int32_t arg_count, + void* arg_types, uint32_t arg_values_size, uint8_t* arg_values) +{ + OSL::ustringhash rs_fmt_specification = OSL::ustringhash_from( + fmt_specification); + auto encoded_types = reinterpret_cast(arg_types); + //auto argValues2 = reinterpret_cast (arg_values); + + + rs_printfmt(exec_ctx, rs_fmt_specification, arg_count, encoded_types, + arg_values_size, + arg_values); //not argValues2 +} + + +OSL_RSOP void +osl_gen_filefmt(OpaqueExecContextPtr exec_ctx, + OSL::ustringhash_pod filename_hash, + OSL::ustringhash_pod fmt_specification, int32_t arg_count, + void* arg_types, uint32_t arg_values_size, uint8_t* arg_values) +{ + OSL::ustringhash rs_fmt_specification = OSL::ustringhash_from( + fmt_specification); + OSL::ustringhash rs_filename = OSL::ustringhash_from(filename_hash); + + auto encoded_types = reinterpret_cast(arg_types); + rs_filefmt(exec_ctx, rs_filename, rs_fmt_specification, arg_count, + encoded_types, arg_values_size, arg_values); +} + +int +get_max_warnings_per_thread(OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + auto ssu = reinterpret_cast( + ec->shadingStateUniform); + return ssu->m_max_warnings_per_thread; +} + +} //namespace pvt + + +OSL_NAMESPACE_EXIT \ No newline at end of file diff --git a/src/liboslexec/opmatrix.cpp b/src/liboslexec/opmatrix.cpp index 2bf99c857a..fbe128a5a1 100644 --- a/src/liboslexec/opmatrix.cpp +++ b/src/liboslexec/opmatrix.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include @@ -22,6 +22,8 @@ #include #include + + OSL_NAMESPACE_ENTER namespace pvt { @@ -134,33 +136,28 @@ osl_transformn_dvmdv(void* result, void* M_, void* v_) #ifndef __CUDACC__ OSL_SHADEOP int -osl_get_matrix(void* sg_, void* r, const char* from) +osl_get_matrix(OpaqueExecContextPtr oec, void* r, const char* from) { - ShaderGlobals* sg = (ShaderGlobals*)sg_; - ShadingStateUniform* ssu = (ShadingStateUniform*)sg->shadingStateUniform; if (HDSTR(from) == STRING_PARAMS(common) - || HDSTR(from) == ssu->m_commonspace_synonym) { + || HDSTR(from) == get_commonspace_synonym(oec)) { MAT(r).makeIdentity(); return true; } if (HDSTR(from) == STRING_PARAMS(shader)) { - rs_get_matrix_xform_time(sg_, MAT(r), sg->shader2common, sg->time); + rs_get_matrix_xform_time(oec, MAT(r), get_shader2common(oec), get_time(oec)); return true; } if (HDSTR(from) == STRING_PARAMS(object)) { - rs_get_matrix_xform_time(sg_, MAT(r), sg->object2common, sg->time); + rs_get_matrix_xform_time(oec, MAT(r), get_object2common(oec), get_time(oec)); return true; } - int ok = rs_get_matrix_space_time(sg_, MAT(r), HDSTR(from), sg->time); + int ok = rs_get_matrix_space_time(oec, MAT(r), HDSTR(from), get_time(oec)); if (!ok) { MAT(r).makeIdentity(); - - if (ssu->m_unknown_coordsys_error) - - { - osl_errorfmt(sg,OSL::ustringhash("Unknown transformation \"{}\""), HDSTR(from)); //SM: Real Entry - - } + if (get_unknown_coordsys_error(oec)) { + OSL::errorfmt(oec, "Unknown transformation \"{}\"", + HDSTR(from)); + } } return ok; } @@ -168,36 +165,31 @@ osl_get_matrix(void* sg_, void* r, const char* from) OSL_SHADEOP int -osl_get_inverse_matrix(void* sg_, void* r, const char* to) +osl_get_inverse_matrix(OpaqueExecContextPtr oec, void* r, const char* to) { - ShaderGlobals* sg = (ShaderGlobals*)sg_; - ShadingStateUniform* ssu = (ShadingStateUniform*)sg->shadingStateUniform; if (HDSTR(to) == STRING_PARAMS(common) - || HDSTR(to) == ssu->m_commonspace_synonym) { + || HDSTR(to) == get_commonspace_synonym(oec)) { MAT(r).makeIdentity(); return true; } - if (HDSTR(to) == STRING_PARAMS(shader)) { - rs_get_inverse_matrix_xform_time(sg_, MAT(r), sg->shader2common, - sg->time); + rs_get_inverse_matrix_xform_time(oec, MAT(r), get_shader2common(oec), + get_time(oec)); return true; } if (HDSTR(to) == STRING_PARAMS(object)) { - rs_get_inverse_matrix_xform_time(sg_, MAT(r), sg->object2common, - sg->time); + rs_get_inverse_matrix_xform_time(oec, MAT(r), get_object2common(oec), + get_time(oec)); return true; } - int ok = rs_get_inverse_matrix_space_time(sg_, MAT(r), HDSTR(to), sg->time); + int ok = rs_get_inverse_matrix_space_time(oec, MAT(r), HDSTR(to), get_time(oec)); if (!ok) { MAT(r).makeIdentity(); - - if (ssu->m_unknown_coordsys_error) - - { - osl_errorfmt(sg, OSL::ustringhash("Unknown transformation \"{}\""), HDSTR(to)); - } + if (get_unknown_coordsys_error(oec)) { + OSL::errorfmt(oec, "Unknown transformation \"{}\"", + HDSTR(to)); + } } return ok; } @@ -205,29 +197,27 @@ osl_get_inverse_matrix(void* sg_, void* r, const char* to) // Implemented by the renderer # define OSL_SHADEOP_EXPORT extern "C" OSL_DLL_EXPORT OSL_SHADEOP_EXPORT OSL_HOSTDEVICE int -osl_get_matrix(void* sg_, void* r, const char* from); +osl_get_matrix(OpaqueExecContextPtr oec, void* r, const char* from); OSL_SHADEOP_EXPORT OSL_HOSTDEVICE int -osl_get_inverse_matrix(void* sg_, void* r, const char* to); +osl_get_inverse_matrix(OpaqueExecContextPtr oec, void* r, const char* to); # undef OSL_SHADEOP_EXPORT #endif // __CUDACC__ OSL_SHADEOP OSL_HOSTDEVICE int -osl_prepend_matrix_from(void* sg_, void* r, const char* from) -{ - ShaderGlobals* sg = (ShaderGlobals*)sg_; +osl_prepend_matrix_from(OpaqueExecContextPtr oec, void* r, const char* from) +{ Matrix44 m; - bool ok = osl_get_matrix(sg, &m, from); + bool ok = osl_get_matrix(oec, &m, from); if (ok) MAT(r) = m * MAT(r); #ifndef __CUDACC__ // TODO: How do we manage this in OptiX? else { - ShadingStateUniform* ssu = (ShadingStateUniform*)sg->shadingStateUniform; - if (ssu->m_unknown_coordsys_error) { - ShadingContext* ctx = (ShadingContext*)(sg)->context; - ctx->errorfmt("Unknown transformation \"{}\"", from); + if (get_unknown_coordsys_error(oec)) { + OSL::errorfmt(oec, "Unknown transformation \"{}\"", + HDSTR(from)); } } #endif @@ -237,11 +227,11 @@ osl_prepend_matrix_from(void* sg_, void* r, const char* from) OSL_SHADEOP OSL_HOSTDEVICE int -osl_get_from_to_matrix(void* sg, void* r, const char* from, const char* to) +osl_get_from_to_matrix(OpaqueExecContextPtr oec, void* r, const char* from, const char* to) { Matrix44 Mfrom, Mto; - int ok = osl_get_matrix((ShaderGlobals*)sg, &Mfrom, from); - ok &= osl_get_inverse_matrix((ShaderGlobals*)sg, &Mto, to); + int ok = osl_get_matrix(oec, &Mfrom, from); + ok &= osl_get_inverse_matrix(oec, &Mto, to); MAT(r) = Mfrom * Mto; return ok; } @@ -249,19 +239,18 @@ osl_get_from_to_matrix(void* sg, void* r, const char* from, const char* to) OSL_SHADEOP OSL_HOSTDEVICE int -osl_transform_triple(void* sg_, void* Pin, int Pin_derivs, void* Pout, +osl_transform_triple(OpaqueExecContextPtr oec, void* Pin, int Pin_derivs, void* Pout, int Pout_derivs, void* from, void* to, int vectype) { - ShaderGlobals* sg = (ShaderGlobals*)sg_; Matrix44 M; int ok; Pin_derivs &= Pout_derivs; // ignore derivs if output doesn't need it if (HDSTR(from) == STRING_PARAMS(common)) - ok = osl_get_inverse_matrix(sg, &M, (const char*)to); + ok = osl_get_inverse_matrix(oec, &M, (const char*)to); else if (HDSTR(to) == STRING_PARAMS(common)) - ok = osl_get_matrix(sg, &M, (const char*)from); + ok = osl_get_matrix(oec, &M, (const char*)from); else - ok = osl_get_from_to_matrix(sg, &M, (const char*)from, (const char*)to); + ok = osl_get_from_to_matrix(oec, &M, (const char*)from, (const char*)to); if (ok) { if (vectype == TypeDesc::POINT) { if (Pin_derivs) @@ -304,21 +293,20 @@ osl_transform_triple(void* sg_, void* Pin, int Pin_derivs, void* Pout, OSL_SHADEOP OSL_HOSTDEVICE int -osl_transform_triple_nonlinear(void* sg_, void* Pin, int Pin_derivs, void* Pout, +osl_transform_triple_nonlinear(OpaqueExecContextPtr oec, void* Pin, int Pin_derivs, void* Pout, int Pout_derivs, void* from, void* to, int vectype) { - ShaderGlobals* sg = (ShaderGlobals*)sg_; #ifndef __CUDACC__ - if (rs_transform_points(sg_, HDSTR(from), HDSTR(to), sg->time, + if (rs_transform_points(oec, HDSTR(from), HDSTR(to), get_time(oec), (const Vec3*)Pin, (Vec3*)Pout, 1, (TypeDesc::VECSEMANTICS)vectype)) { // Renderer had a direct way to transform the points between the // two spaces. if (Pout_derivs) { if (Pin_derivs) { - rs_transform_points(sg_, HDSTR(from), HDSTR(to), sg->time, + rs_transform_points(oec, HDSTR(from), HDSTR(to), get_time(oec), (const Vec3*)Pin + 1, (Vec3*)Pout + 1, 2, TypeDesc::VECTOR); } else { @@ -333,7 +321,7 @@ osl_transform_triple_nonlinear(void* sg_, void* Pin, int Pin_derivs, void* Pout, // Renderer couldn't or wouldn't transform directly // Except in OptiX we're the renderer will directly implement // the transform in osl_transform_triple. - return osl_transform_triple(sg, Pin, Pin_derivs, Pout, Pout_derivs, from, + return osl_transform_triple(oec, Pin, Pin_derivs, Pout, Pout_derivs, from, to, vectype); } diff --git a/src/liboslexec/opmessage.cpp b/src/liboslexec/opmessage.cpp index db4cfb788e..94cb8a7a11 100644 --- a/src/liboslexec/opmessage.cpp +++ b/src/liboslexec/opmessage.cpp @@ -3,8 +3,8 @@ // https://github.com/AcademySoftwareFoundation/OpenShadingLanguage #include "oslexec_pvt.h" +#include #include -#include ///////////////////////////////////////////////////////////////////////// @@ -44,28 +44,19 @@ osl_setmessage(ShaderGlobals* sg, ustring_pod name_, long long type_, void* val, if (m) { if (m->name == name) { // message already exists? - if (m->has_data()) - // {sg->context->errorfmt( - // "message \"{}\" already exists (created here: {}:{})" - // " cannot set again from {}:{}", - // name.c_str(), m->sourcefile.c_str(), m->sourceline, - // sourcefile.c_str(), sourceline); - - - osl_errorfmt(sg, - OSL::ustringhash("message \"{}\" already exists (created here: {}:{}) cannot set again from {}:{}"), + if (m->has_data()) { + OSL::errorfmt( + sg, + "message \"{}\" already exists (created here: {}:{})" + " cannot set again from {}:{}", name, m->sourcefile, m->sourceline, sourcefile, sourceline); - - else // NOTE: this cannot be triggered when strict_messages=false because we won't record "failed" getmessage calls - // sg->context->errorfmt( - // "message \"{}\" was queried before being set (queried here: {}:{})" - // " setting it now ({}:{}) would lead to inconsistent results", - // name.c_str(), m->sourcefile.c_str(), m->sourceline, - // sourcefile.c_str(), sourceline); - osl_errorfmt(sg, - OSL::ustringhash("message \"{}\" was queried before being set (queried here: {}:{}) setting it now ({}:{}) would lead to inconsistent results"), - name, m->sourcefile, m->sourceline, - sourcefile, sourceline); + } else { // NOTE: this cannot be triggered when strict_messages=false because we won't record "failed" getmessage calls + OSL::errorfmt( + sg, + "message \"{}\" was queried before being set (queried here: {}:{})" + " setting it now ({}:{}) would lead to inconsistent results", + name, m->sourcefile, m->sourceline, sourcefile, sourceline); + } return; } } @@ -102,52 +93,22 @@ osl_getmessage(ShaderGlobals* sg, ustring_pod source_, ustring_pod name_, if (m->name == name) { if (m->type != type) { // found message, but types don't match - // sg->context->errorfmt( - // "type mismatch for message \"{}\" ({} as {} here: {}:{})" - // " cannot fetch as {} from {}:{}", - // name.c_str(), m->has_data() ? "created" : "queried", - // m->type == TypeDesc::PTR ? "closure color" - // : m->type.c_str(), - // m->sourcefile.c_str(), m->sourceline, - // is_closure ? "closure color" : type.c_str(), - // sourcefile.c_str(), sourceline); - - ustringhash data_arg; - ustringhash color_arg; - ustringhash closure_arg; - - if(m->has_data()) - { - data_arg = ustringhash_from(USTR("created")); - } - else - { - data_arg = ustringhash_from(USTR("queried")); - } - if(m->type == TypeDesc::PTR) { - color_arg = ustringhash_from(USTR("closure color")); - } - else{ - color_arg = ustringhash_from(USTR(m->type.c_str())); - } - - if(is_closure) - { - closure_arg = ustringhash_from(USTR("closure color")); - } - else - { - closure_arg = ustringhash_from(USTR(type.c_str())); - } - - - osl_errorfmt(sg, - OSL::ustringhash("type mismatch for message \"{name}\" ({data} as {type} here: {sourcefile}:{sourceline}) cannot fetch as {closurearg} from {}:{}"), - name, data_arg, - color_arg, - m->sourcefile, m->sourceline, - closure_arg, - sourcefile, sourceline); + OSL::errorfmt( + sg, + "type mismatch for message \"{}\" ({} as {} here: {}:{})" + " cannot fetch as {} from {}:{}", + name, + m->has_data() ? "created" + : "queried", + m->type == TypeDesc::PTR + ? "closure color" + : m->type.c_str(), + m->sourcefile, + m->sourceline, + is_closure ? "closure color" + : type.c_str(), + sourcefile, + sourceline); return 0; } if (!m->has_data()) { @@ -156,18 +117,14 @@ osl_getmessage(ShaderGlobals* sg, ustring_pod source_, ustring_pod name_, } if (m->layeridx > layeridx) { // found message, but was set by a layer deeper than the one querying the message - // sg->context->errorfmt( - // "message \"{}\" was set by layer #{} ({}:{})" - // " but is being queried by layer #{} ({}:{})" - // " - messages may only be transferred from nodes " - // "that appear earlier in the shading network", - // name.c_str(), m->layeridx, m->sourcefile.c_str(), - // m->sourceline, layeridx, sourcefile.c_str(), sourceline); - - osl_errorfmt(sg, - OSL::ustringhash("message \"{}\" was set by layer #{} ({}:{}) but is being queried by layer #{} ({}:{}) - messages may only be transferred from nodes that appear earlier in the shading network"), - name, m->layeridx, m->sourcefile, - m->sourceline, layeridx, sourcefile, sourceline); + OSL::errorfmt( + sg, + "message \"{}\" was set by layer #{} ({}:{})" + " but is being queried by layer #{} ({}:{})" + " - messages may only be transferred from nodes " + "that appear earlier in the shading network", + name, m->layeridx, m->sourcefile, m->sourceline, layeridx, + sourcefile, sourceline); return 0; } // Message found! diff --git a/src/liboslexec/opnoise.cpp b/src/liboslexec/opnoise.cpp index f39c46e82c..36d78e05fb 100644 --- a/src/liboslexec/opnoise.cpp +++ b/src/liboslexec/opnoise.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include @@ -731,9 +731,7 @@ struct GenericNoise { result.clear_d(); } else { # ifndef __CUDA_ARCH__ - // ((ShadingContext*)sg->context) - // ->errorfmt("Unknown noise type \"{}\"", name); - osl_errorfmt(sg,OSL::ustringhash("Unknown noise type \"{}\""), name); + OSL::errorfmt(sg, "Unknown noise type \"{}\"", name); # else // TODO: find a way to signal this error on the GPU result.clear_d(); @@ -781,9 +779,7 @@ struct GenericNoise { result.clear_d(); } else { # ifndef __CUDA_ARCH__ - // ((ShadingContext*)sg->context) - // ->errorfmt("Unknown noise type \"{}\"", name); - osl_errorfmt(sg,OSL::ustringhash("Unknown noise type \"{}\""), name); + OSL::errorfmt(sg, "Unknown noise type \"{}\"", name); # else // TODO: find a way to signal this error on the GPU result.clear_d(); @@ -828,7 +824,7 @@ struct GenericPNoise { result.clear_d(); } else { # ifndef __CUDA_ARCH__ - osl_errorfmt(sg,OSL::ustringhash("Unknown noise type \"{}\""), name); + OSL::errorfmt(sg, "Unknown noise type \"{}\"", name); # else // TODO: find a way to signal this error on the GPU result.clear_d(); @@ -862,7 +858,7 @@ struct GenericPNoise { result.clear_d(); } else { # ifndef __CUDA_ARCH__ - osl_errorfmt(sg,OSL::ustringhash("Unknown noise type \"{}\""), name); + OSL::errorfmt(sg, "Unknown noise type \"{}\"", name); # else // TODO: find a way to signal this error on the GPU result.clear_d(); diff --git a/src/liboslexec/opstring.cpp b/src/liboslexec/opstring.cpp index bd56254e3c..a68586f8ab 100644 --- a/src/liboslexec/opstring.cpp +++ b/src/liboslexec/opstring.cpp @@ -10,13 +10,12 @@ /// ///////////////////////////////////////////////////////////////////////// -#include #include - #include #include +#include #include "oslexec_pvt.h" @@ -150,27 +149,8 @@ osl_regex_impl(void* sg_, const char* subject_, void* results, int nresults, } } -// Shims to convert llvm gen to rs free function C++ parameter types -// and forward on calls to re free functions. -// TODO: moveto opgen.cpp -OSL_RSOP void -osl_gen_errorfmt(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, - OSL::ustringhash_pod fmt_specification, - int32_t arg_count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues) -{ - - OSL::ustringhash rs_fmt_specification = OSL::ustringhash_from(fmt_specification); - rs_errorfmt(exec_ctx, rs_fmt_specification, - arg_count, - argTypes, - argValuesSize, - argValues); - } - - +// TODO: transition format to from llvm_gen_printf_legacy +// to llvm_gen_print_fmt by providing an osl_gen_formatfmt here OSL_SHADEOP const char* osl_format(const char* format_str, ...) { @@ -181,72 +161,6 @@ osl_format(const char* format_str, ...) return ustring(s).c_str(); } -//#if 0 -//Intent is to remove this and call the renderer service function directly in future PR -OSL_SHADEOP void -osl_printf(ShaderGlobals* sg, const char* format_str, ...) -{ - // Until llvm_gen directly calls rs_printfmt, - // we will need to perform the formating here - // as renderer only accepts the fmt specification - va_list args; - va_start(args, format_str); - std::string s = Strutil::vsprintf(format_str, args); - va_end(args); - osl_printfmt(sg, OSL::ustringhash(s)); -} - -//Intent is to remove this and call the renderer service function directly in future PR -OSL_SHADEOP void -osl_error(ShaderGlobals* sg, const char* format_str, ...) -{ - // Until llvm_gen directly calls rs_errorfmt, - // we will need to perform the formating here - // as renderer only accepts the fmt specification - va_list args; - va_start(args, format_str); - std::string s = Strutil::vsprintf(format_str, args); - va_end(args); - osl_errorfmt(sg, OSL::ustringhash(s)); - -} - -//Intent is to remove this and call the renderer service function directly in future PR -OSL_SHADEOP void -osl_warning(ShaderGlobals* sg, const char* format_str, ...) -{ - ShadingStateUniform* ssu = (ShadingStateUniform*)sg->shadingStateUniform; - if(ssu->m_allow_warnings){ - // Until llvm_gen directly calls rs_warningfmt, - // we will need to perform the formating here - // as renderer only accepts the fmt specification - va_list args; - va_start(args, format_str); - std::string s = Strutil::vsprintf(format_str, args); - va_end(args); - osl_warningfmt(sg, OSL::ustringhash(s)); - } -} - - -//Intent is to remove this and call the renderer service function directly in future PR -OSL_SHADEOP void -osl_fprintf(ShaderGlobals* sg, const char* filename, const char* format_str, - ...) -{ - // Until llvm_gen directly calls rs_filefmt, - // we will need to perform the formating here - // as renderer only accepts the fmt specification - va_list args; - va_start(args, format_str); - std::string s = Strutil::vsprintf(format_str, args); - va_end(args); - osl_filefmt(sg,OSL::ustringhash(filename), OSL::ustringhash(s)); -} -//#endif - - - OSL_SHADEOP int osl_split(const char* str, ustring* results, const char* sep, int maxsplit, int resultslen) diff --git a/src/liboslexec/optexture.cpp b/src/liboslexec/optexture.cpp index 4434477140..6da4fb2aac 100644 --- a/src/liboslexec/optexture.cpp +++ b/src/liboslexec/optexture.cpp @@ -396,8 +396,9 @@ osl_get_textureinfo(void* sg_, const char* name, void* handle, void* dataname, ustringhash em; bool ok = sg->renderer->get_texture_info( USTR(name).uhash(), (RendererServices::TextureHandle*)handle, - sg->context->texture_thread_info(), sg->context, 0 /*FIXME-ptex*/, - USTR(dataname).uhash(), typedesc, data, errormessage ? &em : nullptr); + sg->context->texture_thread_info(), sg, + 0 /*FIXME-ptex*/, USTR(dataname).uhash(), typedesc, data, + errormessage ? &em : nullptr); if (errormessage) *errormessage = ok ? ustringrep_from(Strings::_emptystring_) : ustringrep_from(em); @@ -422,8 +423,9 @@ osl_get_textureinfo_st(void* sg_, const char* name, void* handle, float s, ustringhash em; bool ok = sg->renderer->get_texture_info( USTR(name).uhash(), (RendererServices::TextureHandle*)handle, s, t, - sg->context->texture_thread_info(), sg->context, 0 /*FIXME-ptex*/, - USTR(dataname).uhash(), typedesc, data, errormessage ? &em : nullptr); + sg->context->texture_thread_info(), sg, + 0 /*FIXME-ptex*/, USTR(dataname).uhash(), typedesc, data, + errormessage ? &em : nullptr); if (errormessage) *errormessage = ok ? ustringrep_from(Strings::_emptystring_) : ustringrep_from(em); diff --git a/src/liboslexec/oslexec_pvt.h b/src/liboslexec/oslexec_pvt.h index 5c0a7b89b2..315d9221e2 100644 --- a/src/liboslexec/oslexec_pvt.h +++ b/src/liboslexec/oslexec_pvt.h @@ -623,8 +623,8 @@ class ShadingSystemImpl { void release_context(ShadingContext* ctx); - bool execute(ShadingContext& ctx, ShaderGroup& group, int thread_index, int shadeindex, - ShaderGlobals& ssg, void* userdata_base_ptr, + bool execute(ShadingContext& ctx, ShaderGroup& group, int thread_index, + int shadeindex, ShaderGlobals& ssg, void* userdata_base_ptr, void* output_base_ptr, bool run = true); const void* get_symbol(ShadingContext& ctx, ustring layername, @@ -669,7 +669,10 @@ class ShadingSystemImpl { bool fold_getattribute() const { return m_opt_fold_getattribute; } bool opt_texture_handle() const { return m_opt_texture_handle; } int opt_passes() const { return m_opt_passes; } - int max_warnings_per_thread() const { return m_max_warnings_per_thread; } + int max_warnings_per_thread() const + { + return m_shading_state_uniform.m_max_warnings_per_thread; + } bool countlayerexecs() const { return m_countlayerexecs; } bool lazy_userdata() const { return m_lazy_userdata; } bool userdata_isconnected() const { return m_userdata_isconnected; } @@ -840,7 +843,6 @@ class ShadingSystemImpl { ErrorHandler* m_err; ///< Error handler mutable std::list m_errseen, m_warnseen; static const int m_errseenmax = 32; - mutable mutex m_errmutex; typedef std::map ShaderNameMap; @@ -873,13 +875,11 @@ class ShadingSystemImpl { bool m_lockgeom_default; ///< Default value of lockgeom bool m_strict_messages; ///< Strict checking of message passing usage? bool m_error_repeats; ///< Allow repeats of identical err/warn? - //int m_errseenmax; /// 0) { - // // at least one more to go - // m_max_warnings--; - // //m_shading_state_uniform.allow_warning = true; - // return true; - // } else { - // // we've processed enough with this context - // return false; - // } - - return shadingsys().m_shading_state_uniform.m_allow_warnings; + if (m_max_warnings > 0) { + // at least one more to go + m_max_warnings--; + return true; + } else { + // we've processed enough with this context + return false; + } } // Record an error (or warning, printf, etc.) @@ -2477,11 +2475,7 @@ class OSLEXECPUBLIC ShadingContext { BatchedMessageBuffer m_batched_messages_buffer; ///< Buffer for Batched Message blackboard #endif - int m_max_warnings; ///< To avoid processing too many warnings - // { - // return shadingsys().m_shading_state_uniform.m_max_warnings; - // } - + int m_max_warnings; ///< To avoid processing too many warnings int m_stat_get_userdata_calls; ///< Number of calls to get_userdata int m_stat_layers_executed; ///< Number of layers executed long long m_ticks; ///< Time executing the shader diff --git a/src/liboslexec/rendservices.cpp b/src/liboslexec/rendservices.cpp index a7d7b22dc3..289f0725bc 100644 --- a/src/liboslexec/rendservices.cpp +++ b/src/liboslexec/rendservices.cpp @@ -13,8 +13,8 @@ using namespace OSL::pvt; #include #include -#include - +#include +#include OSL_NAMESPACE_ENTER @@ -156,106 +156,66 @@ RendererServices::get_userdata(bool derivatives, ustringhash name, // return get_userdata(derivatives, ustring_from(name), type, sg, val); } -//Default impl that will go away eventually when we solidify a compile-time sturdy solution + void -RendererServices::errorfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - int32_t arg_count, - const EncodedType *arg_types, - uint32_t arg_values_size, - uint8_t *arg_values) +RendererServices::errorfmt(OSL::ShaderGlobals* sg, + OSL::ustringhash fmt_specification, + int32_t arg_count, const EncodedType* arg_types, + uint32_t /*arg_values_size*/, uint8_t* arg_values) { - ShadingContext *ctx = (ShadingContext*)((ShaderGlobals*)sg)->context; std::string message; - //uint64_t fmt_specification_hash = fmt_specification; - OSL::ustringhash_pod fmt_specification_hash = reinterpret_cast(&fmt_specification); - - journal::construct_message(fmt_specification_hash, arg_count, - arg_types, arg_values_size, - arg_values, message); - - - //Gets us existing default behavior of checking for duplicate messages - //and reusing ShadingContext's ErrorHandler + OSL::decode_message(fmt_specification.hash(), arg_count, arg_types, + arg_values, message); + ShadingContext* ctx = (ShadingContext*)((ShaderGlobals*)sg)->context; ctx->errorfmt(message.c_str()); } -void -RendererServices::warningfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - int32_t arg_count, - const EncodedType *arg_types, - uint32_t arg_values_size, - uint8_t *arg_values) +void +RendererServices::warningfmt(OSL::ShaderGlobals* sg, + OSL::ustringhash fmt_specification, + int32_t arg_count, const EncodedType* arg_types, + uint32_t /*arg_values_size*/, uint8_t* arg_values) { - ShadingContext *ctx = (ShadingContext*)((ShaderGlobals*)sg)->context; - std::string message; - //uint64_t fmt_specification_hash = fmt_specification; - OSL::ustringhash_pod fmt_specification_hash = reinterpret_cast(&fmt_specification); - - - journal::construct_message(fmt_specification_hash, arg_count, - arg_types, arg_values_size, - arg_values, message); - - - //Gets us existing default behavior of checking for duplicate messages - //and reusing ShadingContext's ErrorHandler - ctx->warningfmt(message.c_str()); + ShadingContext* ctx = (ShadingContext*)((ShaderGlobals*)sg)->context; + if (ctx->allow_warnings()) { + std::string message; + OSL::decode_message(fmt_specification.hash(), arg_count, arg_types, + arg_values, message); + ctx->warningfmt(message.c_str()); + } } - void -RendererServices::printfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - int32_t arg_count, - const EncodedType *arg_types, - uint32_t arg_values_size, - uint8_t *arg_values) - +RendererServices::printfmt(OSL::ShaderGlobals* sg, + OSL::ustringhash fmt_specification, + int32_t arg_count, const EncodedType* arg_types, + uint32_t /*arg_values_size*/, uint8_t* arg_values) { - ShadingContext *ctx = (ShadingContext*)((ShaderGlobals*)sg)->context; std::string message; - // uint64_t fmt_specification_hash = fmt_specification; - //uint64_t fmt_specification_hash = ustringrep_from(fmt_specification); - OSL::ustringhash_pod fmt_specification_hash = reinterpret_cast(&fmt_specification); - - - journal::construct_message(fmt_specification_hash, arg_count, - arg_types, arg_values_size, - arg_values, message); - + OSL::decode_message(fmt_specification.hash(), arg_count, arg_types, + arg_values, message); + ShadingContext* ctx = (ShadingContext*)((ShaderGlobals*)sg)->context; ctx->messagefmt(message.c_str()); } -void -RendererServices::filefmt(OSL::ShaderGlobals* sg, - OSL::ustringhash filename_hash, - OSL::ustringhash fmt_specification, - int32_t arg_count, - const EncodedType *arg_types, - uint32_t arg_values_size, - uint8_t *arg_values) +void +RendererServices::filefmt(OSL::ShaderGlobals* sg, + OSL::ustringhash filename_hash, + OSL::ustringhash fmt_specification, int32_t arg_count, + const EncodedType* arg_types, + uint32_t /*arg_values_size*/, uint8_t* arg_values) { - ShadingContext *ctx = (ShadingContext*)((ShaderGlobals*)sg)->context; std::string message; - //uint64_t fmt_specification_hash = fmt_specification; - OSL::ustringhash_pod fmt_specification_hash = reinterpret_cast(&fmt_specification); - - - journal::construct_message(fmt_specification_hash, arg_count, - arg_types, arg_values_size, - arg_values, message); - - //auto filename = OSL::ustring::from_hash(filname_hash) + OSL::decode_message(fmt_specification.hash(), arg_count, arg_types, + arg_values, message); OSL::ustringhash filename_ = OSL::ustringhash_from(filename_hash); - std::string filename (filename_hash.c_str()); - auto file_message = OSL::fmtformat("{}:{}", filename, message); - + std::string filename(filename_hash.c_str()); + auto file_message = OSL::fmtformat("{}:{}", filename, message); + ShadingContext* ctx = (ShadingContext*)((ShaderGlobals*)sg)->context; ctx->messagefmt(file_message.c_str()); } @@ -323,7 +283,7 @@ RendererServices::texture(ustringhash filename, TextureHandle* texture_handle, if (errormessage) { *errormessage = ustringhash(err); } else { - context->errorfmt("[RendererServices::texture] {}", err); + OSL::errorfmt(sg, "[RendererServices::texture] {}", err); } } else if (errormessage) { *errormessage = ustringhash(Strings::unknown); @@ -366,7 +326,7 @@ RendererServices::texture3d(ustringhash filename, TextureHandle* texture_handle, if (errormessage) { *errormessage = ustringhash(err); } else { - sg->context->errorfmt("[RendererServices::texture3d] {}", err); + OSL::errorfmt(sg, "[RendererServices::texture3d] {}", err); } } else if (errormessage) { *errormessage = Strings::unknown.uhash(); @@ -407,8 +367,7 @@ RendererServices::environment(ustringhash filename, if (errormessage) { *errormessage = ustringhash(err); } else { - sg->context->errorfmt("[RendererServices::environment] {}", - err); + OSL::errorfmt(sg, "[RendererServices::environment] {}", err); } } else if (errormessage) { *errormessage = Strings::unknown.uhash(); @@ -420,14 +379,15 @@ RendererServices::environment(ustringhash filename, bool -RendererServices::get_texture_info(ustringhash filename, - TextureHandle* texture_handle, - TexturePerthread* texture_thread_info, - ShadingContext* shading_context, - int subimage, ustringhash dataname, - TypeDesc datatype, void* data, - ustringhash* errormessage) +RendererServices::get_texture_info( + ustringhash filename, TextureHandle* texture_handle, + TexturePerthread* texture_thread_info, + ShaderGlobals* sg, int subimage, + ustringhash dataname, TypeDesc datatype, void* data, + ustringhash* errormessage) { + ShadingContext* shading_context + = (ShadingContext*)((ShaderGlobals*)sg)->context; if (!texture_thread_info) texture_thread_info = shading_context->texture_thread_info(); if (!texture_handle) @@ -443,8 +403,7 @@ RendererServices::get_texture_info(ustringhash filename, if (errormessage) { *errormessage = ustringhash(err); } else { - shading_context->errorfmt( - "[RendererServices::get_texture_info] {}", err); + OSL::errorfmt(sg, "[RendererServices::get_texture_info] {}", err); } } else if (errormessage) { // gettextureinfo failed but did not provide an error, so none should be emitted @@ -459,10 +418,13 @@ RendererServices::get_texture_info(ustringhash filename, bool RendererServices::get_texture_info( ustringhash filename, TextureHandle* texture_handle, float s, float t, - TexturePerthread* texture_thread_info, ShadingContext* shading_context, - int subimage, ustringhash dataname, TypeDesc datatype, void* data, + TexturePerthread* texture_thread_info, + ShaderGlobals* sg, int subimage, + ustringhash dataname, TypeDesc datatype, void* data, ustringhash* errormessage) { + ShadingContext* shading_context + = (ShadingContext*)((ShaderGlobals*)sg)->context; #if OIIO_VERSION >= 20307 // Newer versions of the TextureSystem interface are able to determine the // specific UDIM tile we're using. @@ -484,8 +446,8 @@ RendererServices::get_texture_info( } #endif return get_texture_info(filename, texture_handle, texture_thread_info, - shading_context, subimage, dataname, datatype, data, - errormessage); + sg, subimage, dataname, + datatype, data, errormessage); } diff --git a/src/liboslexec/rs_fallback.cpp b/src/liboslexec/rs_fallback.cpp index faf0d132c8..afd7f21626 100644 --- a/src/liboslexec/rs_fallback.cpp +++ b/src/liboslexec/rs_fallback.cpp @@ -2,156 +2,152 @@ // SPDX-License-Identifier: BSD-3-Clause // https://github.com/AcademySoftwareFoundation/OpenShadingLanguage -#include +#include #include #include +// Fallback is to reroute calls back through the virtual function +// based RendererServices from ShaderGlobals. +// We are intentially hiding ShaderGlobals and RendererServices from +// user supplied render service free functions as they should not +// allowed access to them. +// However to implement the fallback, we allow such access only right here + +// Intentially private to this file +namespace { +inline OSL::ShaderGlobals* +get_sg(OSL::OpaqueExecContextPtr cptr) +{ + return reinterpret_cast(cptr); +} +} // namespace + // Host only fallback implementation of free function renderer services that // simply forward the calls to the existing virtual RendererServices methods OSL_RSOP bool -rs_get_matrix_xform_time(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, - OSL::TransformationPtr from, float time) +rs_get_matrix_xform_time(OSL::OpaqueExecContextPtr exec_ctx, + OSL::Matrix44& result, OSL::TransformationPtr from, + float time) { - auto sg = osl_get_sg(exec_ctx); + auto sg = get_sg(exec_ctx); return sg->renderer->get_matrix(sg, result, from, time); } OSL_RSOP bool -rs_get_inverse_matrix_xform_time(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, +rs_get_inverse_matrix_xform_time(OSL::OpaqueExecContextPtr exec_ctx, + OSL::Matrix44& result, OSL::TransformationPtr xform, float time) { - auto sg = osl_get_sg(exec_ctx); + auto sg = get_sg(exec_ctx); return sg->renderer->get_inverse_matrix(sg, result, xform, time); } OSL_RSOP bool -rs_get_matrix_space_time(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, - OSL::StringParam from, float time) +rs_get_matrix_space_time(OSL::OpaqueExecContextPtr exec_ctx, + OSL::Matrix44& result, OSL::StringParam from, + float time) { - auto sg = osl_get_sg(exec_ctx); + auto sg = get_sg(exec_ctx); return sg->renderer->get_matrix(sg, result, from, time); } OSL_RSOP bool -rs_get_inverse_matrix_space_time(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, - OSL::StringParam to, float time) +rs_get_inverse_matrix_space_time(OSL::OpaqueExecContextPtr exec_ctx, + OSL::Matrix44& result, OSL::StringParam to, + float time) { - auto sg = osl_get_sg(exec_ctx); + auto sg = get_sg(exec_ctx); return sg->renderer->get_inverse_matrix(sg, result, to, time); } OSL_RSOP bool -rs_get_matrix_xform(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, +rs_get_matrix_xform(OSL::OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, OSL::TransformationPtr xform) { - auto sg = osl_get_sg(exec_ctx); + auto sg = get_sg(exec_ctx); return sg->renderer->get_matrix(sg, result, xform); } OSL_RSOP bool -rs_get_inverse_matrix_xform(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, - OSL::TransformationPtr xform) +rs_get_inverse_matrix_xform(OSL::OpaqueExecContextPtr exec_ctx, + OSL::Matrix44& result, OSL::TransformationPtr xform) { - auto sg = osl_get_sg(exec_ctx); + auto sg = get_sg(exec_ctx); return sg->renderer->get_inverse_matrix(sg, result, xform); } OSL_RSOP bool -rs_get_matrix_space(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, +rs_get_matrix_space(OSL::OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, OSL::StringParam from) { - auto sg = osl_get_sg(exec_ctx); + auto sg = get_sg(exec_ctx); return sg->renderer->get_matrix(sg, result, from); } OSL_RSOP bool -rs_get_inverse_matrix_space(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, - OSL::StringParam to) +rs_get_inverse_matrix_space(OSL::OpaqueExecContextPtr exec_ctx, + OSL::Matrix44& result, OSL::StringParam to) { - auto sg = osl_get_sg(exec_ctx); + auto sg = get_sg(exec_ctx); return sg->renderer->get_inverse_matrix(sg, result, to); } OSL_RSOP bool -rs_transform_points(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx, OSL::StringParam from, +rs_transform_points(OSL::OpaqueExecContextPtr exec_ctx, OSL::StringParam from, OSL::StringParam to, float time, const OSL::Vec3* Pin, OSL::Vec3* Pout, int npoints, OSL::TypeDesc::VECSEMANTICS vectype) { - auto sg = osl_get_sg(exec_ctx); + auto sg = get_sg(exec_ctx); return sg->renderer->transform_points(sg, from, to, time, Pin, Pout, npoints, vectype); } OSL_RSOP void -rs_errorfmt_dummy(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx) -{ - -} -OSL_RSOP void -rs_errorfmt(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues) +rs_errorfmt(OSL::OpaqueExecContextPtr exec_ctx, + OSL::ustringhash fmt_specification, int32_t count, + const OSL::EncodedType* argTypes, uint32_t argValuesSize, + uint8_t* argValues) { - - auto sg = osl_get_sg(exec_ctx); - sg->renderer->errorfmt(sg, fmt_specification, count, - argTypes, argValuesSize, - argValues); + auto sg = get_sg(exec_ctx); + sg->renderer->errorfmt(sg, fmt_specification, count, argTypes, + argValuesSize, argValues); } OSL_RSOP void -rs_warningfmt(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues) -{ - auto sg = osl_get_sg(exec_ctx); - sg->renderer->warningfmt(sg, fmt_specification, count, - argTypes, argValuesSize, - argValues); +rs_warningfmt(OSL::OpaqueExecContextPtr exec_ctx, + OSL::ustringhash fmt_specification, int32_t count, + const OSL::EncodedType* argTypes, uint32_t argValuesSize, + uint8_t* argValues) +{ + auto sg = get_sg(exec_ctx); + sg->renderer->warningfmt(sg, fmt_specification, count, argTypes, + argValuesSize, argValues); } - - OSL_RSOP void -rs_printfmt(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues) +rs_printfmt(OSL::OpaqueExecContextPtr exec_ctx, + OSL::ustringhash fmt_specification, int32_t count, + const OSL::EncodedType* argTypes, uint32_t argValuesSize, + uint8_t* argValues) { - auto sg = osl_get_sg(exec_ctx); - sg->renderer->printfmt(sg, fmt_specification, count, - argTypes, argValuesSize, - argValues); + auto sg = get_sg(exec_ctx); + sg->renderer->printfmt(sg, fmt_specification, count, argTypes, + argValuesSize, argValues); } OSL_RSOP void -rs_filefmt(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx, - OSL::ustringhash filename, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues) +rs_filefmt(OSL::OpaqueExecContextPtr exec_ctx, OSL::ustringhash filename, + OSL::ustringhash fmt_specification, int32_t count, + const OSL::EncodedType* argTypes, uint32_t argValuesSize, + uint8_t* argValues) { - - auto sg = osl_get_sg(exec_ctx); - sg->renderer->filefmt(sg, filename, fmt_specification, count, - argTypes, argValuesSize, - argValues); + auto sg = get_sg(exec_ctx); + sg->renderer->filefmt(sg, filename, fmt_specification, count, argTypes, + argValuesSize, argValues); } - - diff --git a/src/liboslexec/runtimeoptimize.cpp b/src/liboslexec/runtimeoptimize.cpp index 642de03344..4b1dc17e0d 100644 --- a/src/liboslexec/runtimeoptimize.cpp +++ b/src/liboslexec/runtimeoptimize.cpp @@ -114,6 +114,10 @@ RuntimeOptimizer::RuntimeOptimizer(ShadingSystemImpl& shadingsys, { memset((char*)&m_shaderglobals, 0, sizeof(ShaderGlobals)); m_shaderglobals.context = shadingcontext(); + // To handle error/warning/print that might be reported through + // the renderer services, we will need to provide the default one + // which will just report through the ShadingContext + m_shaderglobals.renderer = &m_rendererservices; // Disable no_function_return_calls for OptiX renderers, because we // aren't yet set up to support use of debugging symbols for PTX. diff --git a/src/liboslexec/runtimeoptimize.h b/src/liboslexec/runtimeoptimize.h index 20c8bc412b..58bf4531fa 100644 --- a/src/liboslexec/runtimeoptimize.h +++ b/src/liboslexec/runtimeoptimize.h @@ -479,6 +479,7 @@ class RuntimeOptimizer final : public OSOProcessorBase { bool m_opt_batched_analysis; ///< Perform extra analysis required for batched execution? bool m_keep_no_return_function_calls; ///< To generate debug info, keep no return function calls ShaderGlobals m_shaderglobals; ///< Dummy ShaderGlobals + RendererServices m_rendererservices; ///< Dummy RendererServices // Keep track of some things for the whole shader group: typedef std::unordered_map ustringmap_t; diff --git a/src/liboslexec/shading_state_uniform.h b/src/liboslexec/shading_state_uniform.h index 183aa52c03..1667fd4394 100644 --- a/src/liboslexec/shading_state_uniform.h +++ b/src/liboslexec/shading_state_uniform.h @@ -2,6 +2,8 @@ // SPDX-License-Identifier: BSD-3-Clause // https://github.com/AcademySoftwareFoundation/OpenShadingLanguage +#pragma once +#include #include "opcolor.h" OSL_NAMESPACE_ENTER @@ -19,10 +21,26 @@ struct ShadingStateUniform { ColorSystem m_colorsystem; ///< Data for current colorspace ustring m_commonspace_synonym; ///< Synonym for "common" space bool m_unknown_coordsys_error; ///< Error to use unknown xform name? - int m_max_warnings; ///< To avoid processing too many warnings - bool m_allow_warnings; + int m_max_warnings_per_thread; ///< How many warnings to display per thread before giving up? }; +inline bool +get_unknown_coordsys_error(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + ShadingStateUniform* ssu = (ShadingStateUniform*)(ec->shadingStateUniform); + return ssu->m_unknown_coordsys_error; +} + +inline ustring +get_commonspace_synonym(const OpaqueExecContextPtr oec) +{ + auto ec = pvt::get_ec(oec); + ShadingStateUniform* ssu = (ShadingStateUniform*)(ec->shadingStateUniform); + return ssu->m_commonspace_synonym; + +} + } // namespace pvt OSL_NAMESPACE_EXIT \ No newline at end of file diff --git a/src/liboslexec/shadingsys.cpp b/src/liboslexec/shadingsys.cpp index d9d9fa2007..0ba9c8b84f 100644 --- a/src/liboslexec/shadingsys.cpp +++ b/src/liboslexec/shadingsys.cpp @@ -11,6 +11,7 @@ #include "oslexec_pvt.h" #include +#include #include "backendllvm.h" #if OSL_USE_BATCHED # include "batched_backendllvm.h" @@ -22,6 +23,7 @@ #include #include #include +#include #include #include @@ -248,65 +250,70 @@ ShadingSystem::release_context(ShadingContext* ctx) bool -ShadingSystem::execute(ShadingContext& ctx, ShaderGroup& group, int thread_index, int shade_index, +ShadingSystem::execute(ShadingContext& ctx, ShaderGroup& group, + int thread_index, int shade_index, ShaderGlobals& globals, void* userdata_base_ptr, void* output_base_ptr, bool run) { - return m_impl->execute(ctx, group, thread_index, shade_index, globals, userdata_base_ptr, - output_base_ptr, run); + return m_impl->execute(ctx, group, thread_index, shade_index, globals, + userdata_base_ptr, output_base_ptr, run); } bool -ShadingSystem::execute_init(ShadingContext& ctx, ShaderGroup& group, int thread_index, int shade_index, +ShadingSystem::execute_init(ShadingContext& ctx, ShaderGroup& group, + int thread_index, int shade_index, ShaderGlobals& globals, void* userdata_base_ptr, void* output_base_ptr, bool run) { - return ctx.execute_init(group, thread_index, shade_index, globals, userdata_base_ptr, - output_base_ptr, run); + return ctx.execute_init(group, thread_index, shade_index, globals, + userdata_base_ptr, output_base_ptr, run); } bool -ShadingSystem::execute_layer(ShadingContext& ctx, int thread_index, int shade_index, - ShaderGlobals& globals, void* userdata_base_ptr, - void* output_base_ptr, int layernumber) +ShadingSystem::execute_layer(ShadingContext& ctx, int thread_index, + int shade_index, ShaderGlobals& globals, + void* userdata_base_ptr, void* output_base_ptr, + int layernumber) { - return ctx.execute_layer(thread_index, shade_index, globals, userdata_base_ptr, output_base_ptr, - layernumber); + return ctx.execute_layer(thread_index, shade_index, globals, + userdata_base_ptr, output_base_ptr, layernumber); } bool -ShadingSystem::execute_layer(ShadingContext& ctx, int thread_index, int shade_index, - ShaderGlobals& globals, void* userdata_base_ptr, - void* output_base_ptr, ustring layername) +ShadingSystem::execute_layer(ShadingContext& ctx, int thread_index, + int shade_index, ShaderGlobals& globals, + void* userdata_base_ptr, void* output_base_ptr, + ustring layername) { int layernumber = find_layer(*ctx.group(), layername); - return layernumber >= 0 - ? ctx.execute_layer(thread_index, shade_index, globals, userdata_base_ptr, - output_base_ptr, layernumber) - : false; + return layernumber >= 0 ? ctx.execute_layer(thread_index, shade_index, + globals, userdata_base_ptr, + output_base_ptr, layernumber) + : false; } bool -ShadingSystem::execute_layer(ShadingContext& ctx, int thread_index, int shade_index, - ShaderGlobals& globals, void* userdata_base_ptr, - void* output_base_ptr, const ShaderSymbol* symbol) +ShadingSystem::execute_layer(ShadingContext& ctx, int thread_index, + int shade_index, ShaderGlobals& globals, + void* userdata_base_ptr, void* output_base_ptr, + const ShaderSymbol* symbol) { if (!symbol) return false; const Symbol* sym = reinterpret_cast(symbol); int layernumber = sym->layer(); - return layernumber >= 0 - ? ctx.execute_layer(thread_index, shade_index, globals, userdata_base_ptr, - output_base_ptr, layernumber) - : false; + return layernumber >= 0 ? ctx.execute_layer(thread_index, shade_index, + globals, userdata_base_ptr, + output_base_ptr, layernumber) + : false; } #if OSL_USE_BATCHED @@ -1002,13 +1009,11 @@ ShadingSystemImpl::ShadingSystemImpl(RendererServices* renderer, , m_lockgeom_default(true) , m_strict_messages(true) , m_error_repeats(false) - //, m_errseenmax(32) , m_range_checking(true) , m_connection_error(true) , m_greedyjit(false) , m_countlayerexecs(false) , m_relaxed_param_typecheck(false) - , m_max_warnings_per_thread(100) , m_profile(0) , m_optimize(2) , m_opt_simplify_param(true) @@ -1071,18 +1076,9 @@ ShadingSystemImpl::ShadingSystemImpl(RendererServices* renderer, , m_stat_inst_merge_time(0) , m_stat_max_llvm_local_mem(0) { - m_shading_state_uniform.m_commonspace_synonym = ustring("world"); - m_shading_state_uniform.m_unknown_coordsys_error = true; - - if( m_shading_state_uniform.m_max_warnings > 0) - { - m_shading_state_uniform.m_max_warnings--; - m_shading_state_uniform.m_allow_warnings = true; - } - else{ - m_shading_state_uniform.m_allow_warnings = false; - } - + m_shading_state_uniform.m_commonspace_synonym = ustring("world"); + m_shading_state_uniform.m_unknown_coordsys_error = true; + m_shading_state_uniform.m_max_warnings_per_thread = 100; m_stat_shaders_loaded = 0; m_stat_shaders_requested = 0; @@ -1577,7 +1573,8 @@ ShadingSystemImpl::attribute(string_view name, TypeDesc type, const void* val) ATTR_SET("greedyjit", int, m_greedyjit); ATTR_SET("relaxed_param_typecheck", int, m_relaxed_param_typecheck); ATTR_SET("countlayerexecs", int, m_countlayerexecs); - ATTR_SET("max_warnings_per_thread", int, m_max_warnings_per_thread); + ATTR_SET("max_warnings_per_thread", int, + m_shading_state_uniform.m_max_warnings_per_thread); ATTR_SET("max_local_mem_KB", int, m_max_local_mem_KB); ATTR_SET("compile_report", int, m_compile_report); ATTR_SET("max_optix_groupdata_alloc", int, m_max_optix_groupdata_alloc); @@ -1589,8 +1586,6 @@ ShadingSystemImpl::attribute(string_view name, TypeDesc type, const void* val) ATTR_SET("exec_repeat", int, m_exec_repeat); ATTR_SET("opt_warnings", int, m_opt_warnings); ATTR_SET("gpu_opt_error", int, m_gpu_opt_error); - ATTR_SET("allow_warnings", int, - m_shading_state_uniform.m_allow_warnings); ATTR_SET_STRING("commonspace", m_shading_state_uniform.m_commonspace_synonym); ATTR_SET_STRING("debug_groupname", m_debug_groupname); @@ -1664,7 +1659,6 @@ ShadingSystemImpl::attribute(string_view name, TypeDesc type, const void* val) if (name == "error_repeats") { // Special case: setting error_repeats also clears the "previously // seen" error and warning lists. - std::cout<<"inside shadingsys error_repeats and value is: "<context; - const float* vals = (const float*)vals_; + auto ec = pvt::get_ec(sg); + const float* vals = (const float*)vals_; for (int d = 0; d < (has_derivs ? 3 : 1); ++d) { for (int c = firstcheck, e = c + nchecks; c < e; ++c) { int i = d * ncomps + c; if (!OIIO::isfinite(vals[i])) { - ctx->errorfmt("Detected {} value in {}{} at {}:{} (op {})", - vals[i], d > 0 ? "the derivatives of " : "", - USTR(symbolname), USTR(sourcefile), sourceline, - USTR(opname)); + OSL::errorfmt(ec, "Detected {} value in {}{} at {}:{} (op {})", + vals[i], + d > 0 ? "the derivatives of " + : "", + OSL::ustringhash_from(symbolname_), + OSL::ustringhash_from(sourcefile_), sourceline, + OSL::ustringhash_from(opname_)); return; } } @@ -4461,13 +4457,13 @@ osl_naninf_check(int ncomps, const void* vals_, int has_derivs, void* sg, // element of an array. OSL_SHADEOP void osl_uninit_check(long long typedesc_, void* vals_, void* sg, - ustring_pod sourcefile, int sourceline, ustring_pod groupname_, - int layer, ustring_pod layername_, ustring_pod shadername, - int opnum, ustring_pod opname, int argnum, - ustring_pod symbolname, int firstcheck, int nchecks) + ustringhash_pod sourcefile_, int sourceline, + ustringhash_pod groupname_, int layer, + ustringhash_pod layername_, ustringhash_pod shadername_, + int opnum, ustringhash_pod opname_, int argnum, + ustringhash_pod symbolname_, int firstcheck, int nchecks) { TypeDesc typedesc = TYPEDESC(typedesc_); - ShadingContext* ctx = (ShadingContext*)((ShaderGlobals*)sg)->context; bool uninit = false; if (typedesc.basetype == TypeDesc::FLOAT) { float* vals = (float*)vals_; @@ -4494,35 +4490,43 @@ osl_uninit_check(long long typedesc_, void* vals_, void* sg, } } if (uninit) { - ustringrep groupname = USTR(groupname_); - ustringrep layername = USTR(layername_); - ctx->errorfmt( + auto groupname = OSL::ustringhash_from(groupname_); + auto layername = OSL::ustringhash_from(layername_); + OSL::ExecContextPtr ec = pvt::get_ec(sg); + OSL::errorfmt( + ec, "Detected possible use of uninitialized value in {} {} at {}:{} (group {}, layer {} {}, shader {}, op {} '{}', arg {})", - typedesc, USTR(symbolname), USTR(sourcefile), sourceline, - groupname.empty() ? "" : groupname.c_str(), layer, - layername.empty() ? "" : layername.c_str(), - USTR(shadername), opnum, USTR(opname), argnum); + typedesc, OSL::ustringhash_from(symbolname_), + OSL::ustringhash_from(sourcefile_), sourceline, + groupname.empty() ? OSL::ustringhash("") : groupname, + layer, + layername.empty() ? OSL::ustringhash("") : layername, + OSL::ustringhash_from(shadername_), opnum, + OSL::ustringhash_from(opname_), argnum); } } OSL_SHADEOP int -osl_range_check_err(int indexvalue, int length, ustring_pod symname, void* sg, - ustring_pod sourcefile, int sourceline, - ustring_pod groupname_, int layer, ustring_pod layername_, - ustring_pod shadername) +osl_range_check_err(int indexvalue, int length, ustringhash_pod symname_, + void* sg, ustringhash_pod sourcefile_, int sourceline, + ustringhash_pod groupname_, int layer, + ustringhash_pod layername_, ustringhash_pod shadername_) { - ustringrep groupname = USTR(groupname_); - ustringrep layername = USTR(layername_); + auto ec = pvt::get_ec(sg); if (indexvalue < 0 || indexvalue >= length) { - ShadingContext* ctx = (ShadingContext*)((ShaderGlobals*)sg)->context; - ctx->errorfmt( + auto groupname = OSL::ustringhash_from(groupname_); + auto layername = OSL::ustringhash_from(layername_); + OSL::errorfmt( + ec, "Index [{}] out of range {}[0..{}]: {}:{} (group {}, layer {} {}, shader {})", - indexvalue, USTR(symname), length - 1, USTR(sourcefile), sourceline, - groupname.empty() ? "" : groupname.c_str(), layer, - layername.empty() ? "" : layername.c_str(), - USTR(shadername)); + indexvalue, OSL::ustringhash_from(symname_), length - 1, + OSL::ustringhash_from(sourcefile_), sourceline, + groupname.empty() ? OSL::ustringhash("") : groupname, + layer, + layername.empty() ? OSL::ustringhash("") : layername, + OSL::ustringhash_from(shadername_)); if (indexvalue >= length) indexvalue = length - 1; else diff --git a/src/osltoy/osltoyrenderer.cpp b/src/osltoy/osltoyrenderer.cpp index 29d84bb18a..5990e2a8b2 100644 --- a/src/osltoy/osltoyrenderer.cpp +++ b/src/osltoy/osltoyrenderer.cpp @@ -8,12 +8,8 @@ #include #include -#include -#include - #include "osltoyrenderer.h" -#include "render_state.h" using namespace OSL; @@ -540,22 +536,5 @@ OSLToyRenderer::get_camera_screen_window(ShaderGlobals* /*sg*/, bool derivs, return false; } -void -OSLToyRenderer::errorfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - int32_t arg_count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues) -{ - - RenderState* rs = reinterpret_cast(sg->renderstate); - - journal::Writer jw{rs->journal_buffer}; - jw.record_errorfmt(sg->thread_index, sg->shade_index, fmt_specification, arg_count, argTypes, argValuesSize, argValues); - - -} - OSL_NAMESPACE_EXIT diff --git a/src/osltoy/osltoyrenderer.h b/src/osltoy/osltoyrenderer.h index f0c8f165b7..b547e78542 100644 --- a/src/osltoy/osltoyrenderer.h +++ b/src/osltoy/osltoyrenderer.h @@ -145,12 +145,6 @@ class OSLToyRenderer final : public RendererServices { bool get_camera_screen_window(ShaderGlobals* sg, bool derivs, ustring object, TypeDesc type, ustring name, void* val); - void errorfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); //override; }; OSL_NAMESPACE_EXIT diff --git a/src/osltoy/render_state.h b/src/osltoy/render_state.h deleted file mode 100644 index 0533e5baa2..0000000000 --- a/src/osltoy/render_state.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright Contributors to the Open Shading Language project. -// SPDX-License-Identifier: BSD-3-Clause -// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage - -#pragma once - -#include - -#include // for StringParam - -// All the the state free functions in rs_simplerend.cpp will need to do their job -// NOTE: Additional data is here that will be used by rs_simplerend.cpp in future PR's -// procedurally generating ShaderGlobals. -struct RenderState { - void *journal_buffer; -}; - - - diff --git a/src/testrender/render_state.h b/src/testrender/render_state.h deleted file mode 100644 index 3a99f7728f..0000000000 --- a/src/testrender/render_state.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright Contributors to the Open Shading Language project. -// SPDX-License-Identifier: BSD-3-Clause -// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage - -#pragma once - -#include - -#include // for StringParam - -// All the the state free functions in rs_simplerend.cpp will need to do their job -// NOTE: Additional data is here that will be used by rs_simplerend.cpp in future PR's -// procedurally generating ShaderGlobals. -struct RenderState { - void *journal_buffer; - -}; - - - diff --git a/src/testrender/simpleraytracer.cpp b/src/testrender/simpleraytracer.cpp index ea96ffde77..03fa5e7a5d 100644 --- a/src/testrender/simpleraytracer.cpp +++ b/src/testrender/simpleraytracer.cpp @@ -14,8 +14,6 @@ namespace pugi = OIIO::pugi; #include "raytracer.h" #include "shading.h" #include "simpleraytracer.h" - -#include using namespace OSL; OSL_NAMESPACE_ENTER @@ -28,9 +26,6 @@ static TypeDesc TypeFloatArray2(TypeDesc::FLOAT, 2); static TypeDesc TypeFloatArray4(TypeDesc::FLOAT, 4); static TypeDesc TypeIntArray2(TypeDesc::INT, 2); -static bool use_rs_bitcode - = false; // use free function bitcode version of renderer services - // Subclass ErrorHandler @@ -54,7 +49,7 @@ class SimpleRaytracer::ErrorHandler final : public OIIO::ErrorHandler { -SimpleRaytracer::SimpleRaytracer(int num_threads) +SimpleRaytracer::SimpleRaytracer() { m_errhandler.reset(new SimpleRaytracer::ErrorHandler(*this)); @@ -84,30 +79,8 @@ SimpleRaytracer::SimpleRaytracer(int num_threads) = &SimpleRaytracer::get_camera_shutter_open; m_attr_getters[ustring("camera:shutter_close")] = &SimpleRaytracer::get_camera_shutter_close; - - - ///Initialize a Journal Buffer for all threads to use for journaling fmt specification calls. - - uint8_t *buffer = (uint8_t*) malloc(16* 1024 * 1024); - OSL::journal::initialize_buffer(buffer, 16*1024*1024, 1024, num_threads); } -void -SimpleRaytracer::errorfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - int32_t arg_count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues) -{ - - RenderState* rs = reinterpret_cast(sg->renderstate); - - OSL::journal::Writer jw{rs->journal_buffer}; - jw.record_errorfmt(sg->thread_index, sg->shade_index, fmt_specification, arg_count, argTypes, argValuesSize, argValues); - - -} OIIO::ParamValue* @@ -853,16 +826,9 @@ SimpleRaytracer::globals_from_hit(ShaderGlobals& sg, const Ray& r, sg.raytype = r.raytype; sg.flipHandedness = sg.dPdx.cross(sg.dPdy).dot(sg.N) < 0; - if (use_rs_bitcode) - { - sg.renderstate = &testrender_renderstate; - } - else - { // In our SimpleRaytracer, the "renderstate" itself just a pointer to // the ShaderGlobals. sg.renderstate = &sg; - } } Vec3 diff --git a/src/testrender/simpleraytracer.h b/src/testrender/simpleraytracer.h index b3bbf062b8..7220a39d86 100644 --- a/src/testrender/simpleraytracer.h +++ b/src/testrender/simpleraytracer.h @@ -16,21 +16,17 @@ #include "background.h" #include "raytracer.h" #include "sampling.h" -#include "render_state.h" OSL_NAMESPACE_ENTER class SimpleRaytracer : public RendererServices { - public: // Just use 4x4 matrix for transformations typedef Matrix44 Transformation; - RenderState testrender_renderstate; - - SimpleRaytracer(int num_threads); + SimpleRaytracer(); virtual ~SimpleRaytracer() {} // RendererServices support: @@ -92,18 +88,11 @@ class SimpleRaytracer : public RendererServices { // After render, get the pixels into pixelbuf, if they aren't already. virtual void finalize_pixel_buffer() {} - void errorfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); //override; // ShaderGroupRef storage std::vector& shaders() { return m_shaders; } OIIO::ErrorHandler& errhandler() const { return *m_errhandler; } - Camera camera; Scene scene; Background background; diff --git a/src/testrender/testrender.cpp b/src/testrender/testrender.cpp index 437ca39e33..4d249848bc 100644 --- a/src/testrender/testrender.cpp +++ b/src/testrender/testrender.cpp @@ -59,11 +59,7 @@ static bool shadingsys_options_set = false; static bool use_optix = OIIO::Strutil::stoi( OIIO::Sysutil::getenv("TESTSHADE_OPTIX")); -//Testshade thread tracking and assignment. -//Not recommended for production renderer but fine for testshade -std::atomic next_index { 0 }; -constexpr uint32_t uninitialized_thread_index = -1; -thread_local uint32_t this_threads_index = uninitialized_thread_index; + // Set shading system global attributes based on command line options. static void @@ -243,7 +239,7 @@ main(int argc, const char* argv[]) rend = new OptixRaytracer; else #endif - rend = new SimpleRaytracer(num_threads); + rend = new SimpleRaytracer; // Other renderer and global options if (debug1 || verbose) diff --git a/src/testshade/CMakeLists.txt b/src/testshade/CMakeLists.txt index 108a839b6d..96bd6ceeaa 100644 --- a/src/testshade/CMakeLists.txt +++ b/src/testshade/CMakeLists.txt @@ -6,12 +6,6 @@ set ( testshade_srcs testshade.cpp simplerend.cpp ) -if (CMAKE_COMPILER_IS_GNUCC) - #add_definitions("-Wno-error=sign-compare") - #add_definitions("-Wno-error=class-memaccess") - #add_definitions("-Wno-error=unused-variable") - #add_definitions("-Wno-error=switch") -endif() if (OSL_BUILD_BATCHED) list(APPEND testshade_srcs diff --git a/src/testshade/render_state.h b/src/testshade/render_state.h index 04953b9dcd..d4de5012a8 100644 --- a/src/testshade/render_state.h +++ b/src/testshade/render_state.h @@ -19,9 +19,5 @@ struct RenderState { float fov; float hither; float yon; - int dummy = 10; - void *journal_buffer; + void* journal_buffer; }; - - - diff --git a/src/testshade/rs_simplerend.cpp b/src/testshade/rs_simplerend.cpp index 589479df33..78fa6529f6 100644 --- a/src/testshade/rs_simplerend.cpp +++ b/src/testshade/rs_simplerend.cpp @@ -6,8 +6,9 @@ # error OSL_HOST_RS_BITCODE must be defined by your build system. #endif -#include #include +#include +#include #include "render_state.h" @@ -27,8 +28,9 @@ // Keep free functions in sync with virtual function based SimpleRenderer. OSL_RSOP bool -rs_get_matrix_xform_time(OpaqueExecContextPtr exec_ctx/*OSL::ShaderGlobals* */ /*sg*/, OSL::Matrix44& result, - OSL::TransformationPtr xform, float /*time*/) +rs_get_matrix_xform_time(OSL::OpaqueExecContextPtr /*ec*/, + OSL::Matrix44& result, OSL::TransformationPtr xform, + float /*time*/) { // SimpleRenderer doesn't understand motion blur and transformations // are just simple 4x4 matrices. @@ -38,11 +40,11 @@ rs_get_matrix_xform_time(OpaqueExecContextPtr exec_ctx/*OSL::ShaderGlobals* */ / } OSL_RSOP bool -rs_get_inverse_matrix_xform_time(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, +rs_get_inverse_matrix_xform_time(OSL::OpaqueExecContextPtr ec, + OSL::Matrix44& result, OSL::TransformationPtr xform, float time) { - //auto sg = osl_get_sg(exec_ptr); - bool ok = rs_get_matrix_xform_time(exec_ctx/*sg*/, result, xform, time); + bool ok = rs_get_matrix_xform_time(ec, result, xform, time); if (ok) { result.invert(); } @@ -50,8 +52,9 @@ rs_get_inverse_matrix_xform_time(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr } OSL_RSOP bool -rs_get_matrix_space_time(OpaqueExecContextPtr exec_ctx/*OSL::ShaderGlobals* *//*sg*/, OSL::Matrix44& result, - OSL::StringParam from, float /*time*/) +rs_get_matrix_space_time(OSL::OpaqueExecContextPtr /*ec*/, + OSL::Matrix44& result, OSL::StringParam from, + float /*time*/) { if (from == STRING_PARAMS(myspace)) { OSL::Matrix44 Mmyspace; @@ -64,13 +67,13 @@ rs_get_matrix_space_time(OpaqueExecContextPtr exec_ctx/*OSL::ShaderGlobals* *//* } OSL_RSOP bool -rs_get_inverse_matrix_space_time(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, - OSL::StringParam to, float time) +rs_get_inverse_matrix_space_time(OSL::OpaqueExecContextPtr ec, + OSL::Matrix44& result, OSL::StringParam to, + float time) { using OSL::Matrix44; - //RenderState* rs = reinterpret_cast(sg->renderstate); - auto rs = osl_get_rs(exec_ctx); + auto rs = OSL::get_rs(ec); if (to == STRING_PARAMS(camera) || to == STRING_PARAMS(screen) || to == STRING_PARAMS(NDC) || to == STRING_PARAMS(raster)) { Matrix44 M { rs->world_to_camera }; @@ -78,7 +81,6 @@ rs_get_inverse_matrix_space_time(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr if (to == STRING_PARAMS(screen) || to == STRING_PARAMS(NDC) || to == STRING_PARAMS(raster)) { float depthrange = (double)rs->yon - (double)rs->hither; - //OSL::StringParam proj{rs->projection.m_chars}; const auto& proj = rs->projection; if (proj == STRING_PARAMS(perspective)) { @@ -125,7 +127,7 @@ rs_get_inverse_matrix_space_time(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr result = M; return true; } else { - bool ok = rs_get_matrix_space_time(exec_ctx/*sg*/, result, to, time); + bool ok = rs_get_matrix_space_time(ec, result, to, time); if (ok) { result.invert(); } @@ -135,7 +137,7 @@ rs_get_inverse_matrix_space_time(/*OSL::ShaderGlobals* sg*/OpaqueExecContextPtr } OSL_RSOP bool -rs_get_matrix_xform(OpaqueExecContextPtr exec_ctx /*OSL::ShaderGlobals* *//*sg*/, OSL::Matrix44& result, +rs_get_matrix_xform(OSL::OpaqueExecContextPtr /*ec*/, OSL::Matrix44& result, OSL::TransformationPtr xform) { // SimpleRenderer doesn't understand motion blur and transformations @@ -146,10 +148,10 @@ rs_get_matrix_xform(OpaqueExecContextPtr exec_ctx /*OSL::ShaderGlobals* *//*sg*/ } OSL_RSOP bool -rs_get_inverse_matrix_xform(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, +rs_get_inverse_matrix_xform(OSL::OpaqueExecContextPtr ec, OSL::Matrix44& result, OSL::TransformationPtr xform) { - bool ok = rs_get_matrix_xform(exec_ctx, result, xform); + bool ok = rs_get_matrix_xform(ec, result, xform); if (ok) { result.invert(); } @@ -158,7 +160,7 @@ rs_get_inverse_matrix_xform(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec } OSL_RSOP bool -rs_get_matrix_space(OpaqueExecContextPtr exec_ctx/*OSL::ShaderGlobals* *//*sg*/, OSL::Matrix44& /*result*/, +rs_get_matrix_space(OSL::OpaqueExecContextPtr /*ec*/, OSL::Matrix44& /*result*/, OSL::StringParam from) { if (from == STRING_PARAMS(myspace)) { @@ -169,10 +171,10 @@ rs_get_matrix_space(OpaqueExecContextPtr exec_ctx/*OSL::ShaderGlobals* *//*sg*/, } OSL_RSOP bool -rs_get_inverse_matrix_space(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, OSL::Matrix44& result, +rs_get_inverse_matrix_space(OSL::OpaqueExecContextPtr ec, OSL::Matrix44& result, OSL::StringParam to) { - bool ok = rs_get_matrix_space(/*sg*/exec_ctx, result, to); + bool ok = rs_get_matrix_space(ec, result, to); if (ok) { result.invert(); } @@ -180,7 +182,7 @@ rs_get_inverse_matrix_space(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec } OSL_RSOP bool -rs_transform_points(/*OSL::ShaderGlobals* */ OpaqueExecContextPtr exec_ctx/*sg*/, OSL::StringParam /*from*/, +rs_transform_points(OSL::OpaqueExecContextPtr /*ec*/, OSL::StringParam /*from*/, OSL::StringParam /*to*/, float /*time*/, const OSL::Vec3* /*Pin*/, OSL::Vec3* /*Pout*/, int /*npoints*/, OSL::TypeDesc::VECSEMANTICS /*vectype*/) @@ -191,129 +193,57 @@ rs_transform_points(/*OSL::ShaderGlobals* */ OpaqueExecContextPtr exec_ctx/*sg*/ OSL_RSOP void -rs_errorfmt_dummy(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx) +rs_errorfmt(OSL::OpaqueExecContextPtr ec, OSL::ustringhash fmt_specification, + int32_t arg_count, const OSL::EncodedType* argTypes, + uint32_t argValuesSize, uint8_t* argValues) { - auto rs = osl_get_rs(exec_ctx); - + auto rs = OSL::get_rs(ec); - OSL::journal::Writer jw{rs->journal_buffer}; - //jw.record_errorfmt(sg->thread_index, sg->shade_index, rs_fmt_specification, arg_count, argTypes, argValuesSize, argValues); + OSL::journal::Writer jw { rs->journal_buffer }; + jw.record_errorfmt(OSL::get_thread_index(ec), OSL::get_shade_index(ec), + fmt_specification, arg_count, argTypes, argValuesSize, + argValues); } OSL_RSOP void -rs_errorfmt(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, - OSL::ustringhash fmt_specification, - //OSL::ustringhash fmt_specification, - int32_t arg_count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues) +rs_warningfmt(OSL::OpaqueExecContextPtr ec, OSL::ustringhash fmt_specification, + int32_t arg_count, const OSL::EncodedType* argTypes, + uint32_t argValuesSize, uint8_t* argValues) { - //RenderState* rs = reinterpret_cast(sg->renderstate); - auto rs = osl_get_rs(exec_ctx); - auto sg = osl_get_sg(exec_ctx); - // auto shade_index = osl_get_shade_index(exec_ctx); - // auto thread_index = osl_get_thread_index(exec_ctx); + auto rs = OSL::get_rs(ec); - //OSL::ustringhash rs_fmt_specification = OSL::ustringhash_from(fmt_specification); -// OSL::ustringhash rs_fmt_specification{fmt_specification}; - - OSL::journal::Writer jw{rs->journal_buffer}; - jw.record_errorfmt(sg->thread_index, sg->shade_index, fmt_specification, arg_count, argTypes, argValuesSize, argValues); + OSL::journal::Writer jw { rs->journal_buffer }; + jw.record_warningfmt(OSL::get_max_warnings_per_thread(ec), + OSL::get_thread_index(ec), OSL::get_shade_index(ec), + fmt_specification, arg_count, argTypes, argValuesSize, + argValues); } -OSL_RSOP void -rs_warningfmt(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, - OSL::ustringhash fmt_specification, - int32_t arg_count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues) -{ - //RenderState* rs = reinterpret_cast(sg->renderstate); - // auto rs = osl_get_rs(exec_ctx); - //OSL::ShaderGlobals* sg = reinterpret_cast(exec_ctx); - - - auto sg = osl_get_sg(exec_ctx); - - RenderState* rs = reinterpret_cast(sg->renderstate); //SM: Becomes unreachable if I dont cast like so - - // OSL::ustringhash rs_fmt_specification = OSL::ustringhash_from(fmt_specification); - // std::cout<<"************************"<dummy<dummy<journal_buffer}; - - jw.record_warningfmt(sg->thread_index, sg->shade_index, fmt_specification, arg_count, argTypes, argValuesSize, argValues); - -} OSL_RSOP void -rs_printffmt(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, - OSL::ustringhash fmt_specification, - int32_t arg_count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues) +rs_printfmt(OSL::OpaqueExecContextPtr ec, OSL::ustringhash fmt_specification, + int32_t arg_count, const OSL::EncodedType* argTypes, + uint32_t argValuesSize, uint8_t* argValues) { - //RenderState* rs = reinterpret_cast(sg->renderstate); - auto rs = osl_get_rs(exec_ctx); - auto sg = osl_get_sg(exec_ctx); - //OSL::ustringhash rs_fmt_specification = OSL::ustringhash_from(fmt_specification); + auto rs = OSL::get_rs(ec); - OSL::journal::Writer jw{rs->journal_buffer}; - jw.record_printfmt(sg->thread_index, sg->shade_index, fmt_specification, arg_count, argTypes, argValuesSize, argValues); + OSL::journal::Writer jw { rs->journal_buffer }; + jw.record_printfmt(OSL::get_thread_index(ec), OSL::get_shade_index(ec), + fmt_specification, arg_count, argTypes, argValuesSize, + argValues); } + OSL_RSOP void -rs_filefmt(/*OSL::ShaderGlobals* sg*/ OpaqueExecContextPtr exec_ctx, - OSL::ustringhash filename_hash, - OSL::ustringhash fmt_specification, - int32_t arg_count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues) +rs_filefmt(OSL::OpaqueExecContextPtr ec, OSL::ustringhash filename_hash, + OSL::ustringhash fmt_specification, int32_t arg_count, + const OSL::EncodedType* argTypes, uint32_t argValuesSize, + uint8_t* argValues) { - //RenderState* rs = reinterpret_cast(sg->renderstate); - auto rs = osl_get_rs(exec_ctx); - auto sg = osl_get_sg(exec_ctx); - OSL::ustringhash rs_fmt_specification = OSL::ustringhash_from(fmt_specification); - OSL::ustringhash rs_filename_hash = OSL::ustringhash_from(filename_hash); - - OSL::journal::Writer jw{rs->journal_buffer}; - jw.record_filefmt(sg->thread_index, sg->shade_index, filename_hash, fmt_specification, arg_count, argTypes, argValuesSize, argValues); -} - - -// OSL_RSOP void -// rs_messagefmt(OSL::ShaderGlobals* sg, -// OSL::ustringhash fmt_specification, -// int32_t arg_count, -// const EncodedType *argTypes, -// uint32_t argValuesSize, -// uint8_t *argValues) -// { -// RenderState* rs = reinterpret_cast(sg->renderstate); - -// journal::Writer jw{rs->journal_buffer}; -// jw.record_message(sg->thread_index, sg->shade_index, fmt_specification, arg_count, argTypes, argValuesSize, argValues); - -// } - -// OSL_RSOP void -// rs_infofmt(OSL::ShaderGlobals* sg, -// OSL::ustringhash fmt_specification, -// int32_t arg_count, -// const EncodedType *argTypes, -// uint32_t argValuesSize, -// uint8_t *argValues) -// { -// RenderState* rs = reinterpret_cast(sg->renderstate); - -// OSL::journal::Writer jw{rs->journal_buffer}; -// jw.record_info(sg->thread_index, sg->shade_index, fmt_specification, arg_count, argTypes, argValuesSize, argValues); -// } + auto rs = OSL::get_rs(ec); + OSL::journal::Writer jw { rs->journal_buffer }; + jw.record_filefmt(OSL::get_thread_index(ec), OSL::get_shade_index(ec), + filename_hash, fmt_specification, arg_count, argTypes, + argValuesSize, argValues); +} diff --git a/src/testshade/simplerend.cpp b/src/testshade/simplerend.cpp index 2da2ef47a6..cf718e5a3b 100644 --- a/src/testshade/simplerend.cpp +++ b/src/testshade/simplerend.cpp @@ -5,10 +5,10 @@ #include -#include -#include #include +#include #include +#include #include "simplerend.h" @@ -813,75 +813,58 @@ SimpleRenderer::export_state(RenderState& state) const } void -SimpleRenderer::errorfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - int32_t arg_count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues) +SimpleRenderer::errorfmt(OSL::ShaderGlobals* sg, + OSL::ustringhash fmt_specification, int32_t arg_count, + const EncodedType* arg_types, uint32_t arg_values_size, + uint8_t* argValues) { - - RenderState* rs = reinterpret_cast(sg->renderstate); - - //std::cout<<"Inside simplerender::errorfmt"<journal_buffer}; - jw.record_errorfmt(sg->thread_index, sg->shade_index, fmt_specification, arg_count, argTypes, argValuesSize, argValues); - - + RenderState* rs = reinterpret_cast(sg->renderstate); + OSL::journal::Writer jw { rs->journal_buffer }; + jw.record_errorfmt(OSL::get_thread_index(sg), OSL::get_shade_index(sg), + fmt_specification, arg_count, arg_types, arg_values_size, + argValues); } void -SimpleRenderer::warningfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - int32_t arg_count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues) +SimpleRenderer::warningfmt(OSL::ShaderGlobals* sg, + OSL::ustringhash fmt_specification, + int32_t arg_count, const EncodedType* arg_types, + uint32_t arg_values_size, uint8_t* argValues) { - - RenderState* rs = reinterpret_cast(sg->renderstate); - - - OSL::journal::Writer jw{rs->journal_buffer}; - jw.record_warningfmt(sg->thread_index, sg->shade_index, fmt_specification, arg_count, argTypes, argValuesSize, argValues); - - + RenderState* rs = reinterpret_cast(sg->renderstate); + OSL::journal::Writer jw { rs->journal_buffer }; + jw.record_warningfmt(OSL::get_max_warnings_per_thread(sg), + OSL::get_thread_index(sg), OSL::get_shade_index(sg), + fmt_specification, arg_count, arg_types, arg_values_size, + argValues); } - void -SimpleRenderer::printfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - int32_t arg_count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues) +SimpleRenderer::printfmt(OSL::ShaderGlobals* sg, + OSL::ustringhash fmt_specification, int32_t arg_count, + const EncodedType* arg_types, uint32_t arg_values_size, + uint8_t* argValues) { - - RenderState* rs = reinterpret_cast(sg->renderstate); - - - OSL::journal::Writer jw{rs->journal_buffer}; - jw.record_printfmt(sg->thread_index, sg->shade_index, fmt_specification, arg_count, argTypes, argValuesSize, argValues); - - + RenderState* rs = reinterpret_cast(sg->renderstate); + OSL::journal::Writer jw { rs->journal_buffer }; + jw.record_printfmt(OSL::get_thread_index(sg), OSL::get_shade_index(sg), + fmt_specification, arg_count, arg_types, arg_values_size, + argValues); } void -SimpleRenderer::filefmt(OSL::ShaderGlobals* sg, - OSL::ustringhash filename_hash, - OSL::ustringhash fmt_specification, - int32_t arg_count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues) +SimpleRenderer::filefmt(OSL::ShaderGlobals* sg, OSL::ustringhash filename_hash, + OSL::ustringhash fmt_specification, int32_t arg_count, + const EncodedType* arg_types, uint32_t arg_values_size, + uint8_t* argValues) { RenderState* rs = reinterpret_cast(sg->renderstate); - - OSL::journal::Writer jw{rs->journal_buffer}; - jw.record_filefmt(sg->thread_index, sg->shade_index, filename_hash, fmt_specification, arg_count, argTypes, argValuesSize, argValues); + OSL::journal::Writer jw { rs->journal_buffer }; + jw.record_filefmt(OSL::get_thread_index(sg), OSL::get_shade_index(sg), + filename_hash, fmt_specification, arg_count, arg_types, + arg_values_size, argValues); } diff --git a/src/testshade/simplerend.h b/src/testshade/simplerend.h index 6fd5e20598..b703bac96c 100644 --- a/src/testshade/simplerend.h +++ b/src/testshade/simplerend.h @@ -69,37 +69,19 @@ class SimpleRenderer : public RendererServices { bool getmessage(ShaderGlobals* sg, ustringhash source, ustringhash name, TypeDesc type, void* val, bool derivatives) override; - - void errorfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); - - void warningfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); - - - void printfmt(OSL::ShaderGlobals* sg, - OSL::ustringhash fmt_specification, - int32_t count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); - - void filefmt(OSL::ShaderGlobals* sg, - OSL::ustringhash filename_hash, - OSL::ustringhash fmt_specification, - int32_t arg_count, - const EncodedType *argTypes, - uint32_t argValuesSize, - uint8_t *argValues); - + void errorfmt(OSL::ShaderGlobals* sg, OSL::ustringhash fmt_specification, + int32_t count, const EncodedType* argTypes, + uint32_t argValuesSize, uint8_t* argValues); + void warningfmt(OSL::ShaderGlobals* sg, OSL::ustringhash fmt_specification, + int32_t count, const EncodedType* argTypes, + uint32_t argValuesSize, uint8_t* argValues); + void printfmt(OSL::ShaderGlobals* sg, OSL::ustringhash fmt_specification, + int32_t count, const EncodedType* argTypes, + uint32_t argValuesSize, uint8_t* argValues); + void filefmt(OSL::ShaderGlobals* sg, OSL::ustringhash filename_hash, + OSL::ustringhash fmt_specification, int32_t arg_count, + const EncodedType* argTypes, uint32_t argValuesSize, + uint8_t* argValues); // Set and get renderer attributes/options void attribute(string_view name, TypeDesc type, const void* value); diff --git a/src/testshade/testshade.cpp b/src/testshade/testshade.cpp index 0e3e7d7354..34878f22cb 100644 --- a/src/testshade/testshade.cpp +++ b/src/testshade/testshade.cpp @@ -25,11 +25,11 @@ #include #include +#include +#include #include #include #include -#include -#include #if OSL_USE_BATCHED # include #endif @@ -121,49 +121,49 @@ static char* output_base_ptr = nullptr; static bool use_rs_bitcode = false; // use free function bitcode version of renderer services -//Testshade thread tracking and assignment. -//Not recommended for production renderer but fine for testshade -std::atomic next_index { 0 }; +static int jbufferMB = 16; + +// Testshade thread tracking and assignment. +// Not recommended for production renderer but fine for testshade + +std::atomic next_thread_index { 0 }; constexpr uint32_t uninitialized_thread_index = -1; -thread_local uint32_t this_threads_index = uninitialized_thread_index; - - - -// class Report2Console : public OSL::journal::Reporter -// { -// public: - - -// void report_error(int thread_index, int shade_index, const OSL::string_view & message) -// { -// //std::cout<<"DANGER!!!"<execute(*ctx, *shadergroup, thread_index, shadeindex, - shaderglobals, userdata_base_ptr, - output_base_ptr); //this is called + shadingsys->execute(*ctx, *shadergroup, thread_index, + shadeindex, shaderglobals, + userdata_base_ptr, output_base_ptr); } else { // Explicit list of entries to call in order - shadingsys->execute_init(*ctx, *shadergroup, thread_index, shadeindex, - shaderglobals, userdata_base_ptr, - output_base_ptr); + shadingsys->execute_init(*ctx, *shadergroup, thread_index, + shadeindex, shaderglobals, + userdata_base_ptr, output_base_ptr); if (entrylayer_symbols.size()) { for (size_t i = 0, e = entrylayer_symbols.size(); i < e; ++i) - shadingsys->execute_layer(*ctx, thread_index, shadeindex, - shaderglobals, + shadingsys->execute_layer(*ctx, thread_index, + shadeindex, shaderglobals, userdata_base_ptr, output_base_ptr, entrylayer_symbols[i]); } else { for (size_t i = 0, e = entrylayer_index.size(); i < e; ++i) - shadingsys->execute_layer(*ctx, thread_index, shadeindex, - shaderglobals, + shadingsys->execute_layer(*ctx, thread_index, + shadeindex, shaderglobals, userdata_base_ptr, output_base_ptr, entrylayer_index[i]); @@ -2095,21 +2091,32 @@ test_shade(int argc, const char* argv[]) rend->export_state(theRenderState); } - double setuptime = timer.lap(); if (warmup) rend->warmup(); double warmuptime = timer.lap(); - ///Initialize a Journal Buffer for all threads to use for journaling fmt specification calls. + //Check jbuffer value from user + if (jbufferMB <= 0) { + jbufferMB = 1; //default value for sufficient recording space. + } + + //Initialize a Journal Buffer for all threads to use for journaling fmt specification calls. + const size_t jbuffer_bytes = jbufferMB * 1024 * 1024; + std::unique_ptr buffer((uint8_t*)malloc(jbuffer_bytes)); + constexpr int jbuffer_pagesize = 1024; + bool init_buffer_success + = OSL::journal::initialize_buffer(buffer.get(), jbuffer_bytes, + jbuffer_pagesize, num_threads); + + if (!init_buffer_success) { + std::cout << "Buffer allocation failed" << std::endl; + } - uint8_t *buffer = (uint8_t*) malloc(16* 1024 * 1024); - OSL::journal::initialize_buffer(buffer, 16*1024*1024, 1024, num_threads); //Send the populated Journal Buffer to the renderer - theRenderState.journal_buffer = buffer; - //std::cout<<"Testshade.cpp theRenderState.journalBuffer: "<<(void *) theRenderState.journal_buffer < void { - shade_region(rend, num_threads, shadergroup.get(), sub_roi, save); + shade_region(rend, shadergroup.get(), sub_roi, save); }); } #endif @@ -2167,69 +2174,24 @@ test_shade(int argc, const char* argv[]) pv.data()); } } - } //Iters end - - - int error_repeats; //if set to non-zero, turns off suppression of multiple identical errors and warnings - shadingsys->getattribute("error_repeats", error_repeats); - - int errseenmax; //Add from testshade as a constant - shadingsys->getattribute("errseenmax", errseenmax); - - bool limit_errors = false; - - if(error_repeats==1) - - { - limit_errors = false; - } - else - { - limit_errors = true; } - //journal::TrackRecentlyReported tracker_error_warnings (true, errseenmax, true, errseenmax); - //journal::Report2ErrorHandler report2ErrHandler(&errhandler, tracker_error_warnings); - - //if(error_repeats != 0)/*==false*/ //Do not limit errors; show all repeats - //{ - // std::cout<<"Inside testshade: do not limit errors: "<getattribute("error_repeats", error_repeats); + bool limit_errors = !error_repeats; + bool limit_warnings = !error_repeats; + const int error_history_capacity = 25; + const int warning_history_capacity = 25; + + journal::TrackRecentlyReported tracker_error_warnings( + limit_errors, error_history_capacity, limit_warnings, + warning_history_capacity); + TestshadeReporter reporter(&errhandler, tracker_error_warnings); + OSL::journal::Reader jreader(buffer.get(), reporter); + jreader.process(); + // Need to call journal::initialize_buffer before re-using the buffer double runtime = timer.lap(); diff --git a/testsuite/example-deformer/osldeformer.cpp b/testsuite/example-deformer/osldeformer.cpp index 589c128cb8..58f5f24442 100644 --- a/testsuite/example-deformer/osldeformer.cpp +++ b/testsuite/example-deformer/osldeformer.cpp @@ -114,6 +114,11 @@ class MyRendererServices final : public OSL::RendererServices { #endif }; +//Osldeformer thread tracking and assignment. +//Not recommended for production renderer but fine for osldeformer +std::atomic next_thread_index { 0 }; +constexpr uint32_t uninitialized_thread_index = -1; +thread_local uint32_t this_threads_index = uninitialized_thread_index; int @@ -284,7 +289,14 @@ main(int argc, char* argv[]) // Run the shader (will automagically optimize and JIT the first // time it executes). - shadsys->execute(*ctx, *mygroup.get(), /*shade point index= */ i, + + if(this_threads_index == uninitialized_thread_index) { + + this_threads_index = next_thread_index.fetch_add(1u); + } + int thread_index = this_threads_index; + + shadsys->execute(*ctx, *mygroup.get(), thread_index, /*shade point index= */ i, shaderglobals, /*userdata arena start=*/&userdata, /*output arena start=*/&Pout); diff --git a/testsuite/test-fmt-arrays/ref/out.txt b/testsuite/test-fmt-arrays/ref/out.txt new file mode 100644 index 0000000000..a68f1c0c0a --- /dev/null +++ b/testsuite/test-fmt-arrays/ref/out.txt @@ -0,0 +1,16 @@ +Compiled test_arrays.osl -> test_arrays.oso +printf arrays: + +Output Cout to test_arrays.tif +Int array values 5 6 7 8 + Float array values 6.600000 7.700000 8.433430 8.945454 0.000000 + One shelf array element's width 1.000000 +Int array values 5 6 7 8 + Float array values 6.600000 7.700000 8.433430 8.945454 0.000000 + One shelf array element's width 2.000000 +Int array values 5 6 7 8 + Float array values 6.600000 7.700000 8.433430 8.945454 0.000000 + One shelf array element's width 1.000000 +Int array values 5 6 7 8 + Float array values 6.600000 7.700000 8.433430 8.945454 0.000000 + One shelf array element's width 2.000000 diff --git a/testsuite/test-fmt-arrays/run.py b/testsuite/test-fmt-arrays/run.py new file mode 100644 index 0000000000..5786005163 --- /dev/null +++ b/testsuite/test-fmt-arrays/run.py @@ -0,0 +1,7 @@ +# Copyright Contributors to the Open Shading Language project. +# SPDX-License-Identifier: BSD-3-Clause +# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +command = "echo printf arrays:>> out.txt 2>&1 ;\n" +command += testshade("-t 1 -g 2 2 -od uint8 -o Cout test_arrays.tif test_arrays") + diff --git a/testsuite/test-fmt-arrays/test_arrays.osl b/testsuite/test-fmt-arrays/test_arrays.osl new file mode 100644 index 0000000000..d8b93fd1cf --- /dev/null +++ b/testsuite/test-fmt-arrays/test_arrays.osl @@ -0,0 +1,33 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +struct shelf{ + +float w; +float h; +float d; + +}; + +shader test_arrays(output float Cout = 0.0) +{ + +int int_array[4] = {5,6,7,8}; +float float_array[5] = {6.6, 7.7,8.43343,8.94545344}; + +shelf shelf_array[4]; + +for(int i = 0; i<4;i++) +{ + shelf_array[i].w = P[0]/i+1; + shelf_array[i].h = P[0]/i+2; + shelf_array[i].d = P[0]/i+8; + +} + +printf("Int array values %d\n ", int_array); +printf("Float array values %f\n ", float_array); +printf("One shelf array element's width %f \n", shelf_array[1].w); + +} diff --git a/testsuite/test-fmt-cxpf/ref/out.txt b/testsuite/test-fmt-cxpf/ref/out.txt new file mode 100644 index 0000000000..51c220a74e --- /dev/null +++ b/testsuite/test-fmt-cxpf/ref/out.txt @@ -0,0 +1,180 @@ +Compiled test_cxpf.osl -> test_cxpf.oso +printf: + +Output Cout to test_cxpf.tif +The values at 2.34 and 7.800000 are 5, 6.400000, 123.456001, 8.323200, 7.999990 + +The value is spam +The value is fish and 12 +Give me unmatched braces {{{ +The value is 3 and {{67}} +TEA time is 4.093330 PM +Int arr_col[3]: 0 0 1 +Float color(): 0.450000 0.370000 0.800000 +Int color() only printable as floats: 0.000000 0.000000 1.000000 +Varying float color(): 0.000000 0.000000 0.000000 +Int struct: a.int1: 12 +Int struct: a.int2: 42 +The value is 4.5700 and 23.4 +The value is 12 and 19.450001 at ranges 3.400000 and 5.400000 + +printf():The value is 1.23231995 and 19.453 + +The value is 2.345500 + +The value is 23 and 45 + +The value is 27 and 55 + +The value is %0.8 +Simple printf +0xa +a +11 +011 +00000123 +56678 +00000000678123 +00012 +1.300000 +05.666600 ++678 ++0012 +{****678 ****} +****678 **** +The value is 17 and 2d + +The value is 2.300000e+00,6.780000,3.4 +4.53e+01 +The values at 2.34 and 7.800000 are 5, 6.400000, 123.456001, 8.323200, 7.999990 + +The value is spam +The value is fish and 12 +Give me unmatched braces {{{ +The value is 3 and {{67}} +TEA time is 4.093330 PM +Int arr_col[3]: 0 0 1 +Float color(): 0.450000 0.370000 0.800000 +Int color() only printable as floats: 0.000000 0.000000 1.000000 +Varying float color(): 0.294118 0.000000 0.454545 +Int struct: a.int1: 12 +Int struct: a.int2: 42 +The value is 4.5700 and 23.4 +The value is 12 and 19.450001 at ranges 3.400000 and 5.400000 + +printf():The value is 1.23231995 and 19.453 + +The value is 2.345500 + +The value is 23 and 45 + +The value is 27 and 55 + +The value is %0.8 +Simple printf +0xa +a +11 +011 +00000123 +56678 +00000000678123 +00012 +1.300000 +05.666600 ++678 ++0012 +{****678 ****} +****678 **** +The value is 17 and 2d + +The value is 2.300000e+00,6.780000,3.4 +4.53e+01 +The values at 2.34 and 7.800000 are 5, 6.400000, 123.456001, 8.323200, 7.999990 + +The value is spam +The value is fish and 12 +Give me unmatched braces {{{ +The value is 3 and {{67}} +TEA time is 4.093330 PM +Int arr_col[3]: 0 0 1 +Float color(): 0.450000 0.370000 0.800000 +Int color() only printable as floats: 0.000000 0.000000 1.000000 +Varying float color(): 0.000000 0.161290 0.000000 +Int struct: a.int1: 12 +Int struct: a.int2: 42 +The value is 4.5700 and 23.4 +The value is 12 and 19.450001 at ranges 3.400000 and 5.400000 + +printf():The value is 1.23231995 and 19.453 + +The value is 2.345500 + +The value is 23 and 45 + +The value is 27 and 55 + +The value is %0.8 +Simple printf +0xa +a +11 +011 +00000123 +56678 +00000000678123 +00012 +1.300000 +05.666600 ++678 ++0012 +{****678 ****} +****678 **** +The value is 17 and 2d + +The value is 2.300000e+00,6.780000,3.4 +4.53e+01 +The values at 2.34 and 7.800000 are 5, 6.400000, 123.456001, 8.323200, 7.999990 + +The value is spam +The value is fish and 12 +Give me unmatched braces {{{ +The value is 3 and {{67}} +TEA time is 4.093330 PM +Int arr_col[3]: 0 0 1 +Float color(): 0.450000 0.370000 0.800000 +Int color() only printable as floats: 0.000000 0.000000 1.000000 +Varying float color(): 0.294118 0.161290 0.454545 +Int struct: a.int1: 12 +Int struct: a.int2: 42 +The value is 4.5700 and 23.4 +The value is 12 and 19.450001 at ranges 3.400000 and 5.400000 + +printf():The value is 1.23231995 and 19.453 + +The value is 2.345500 + +The value is 23 and 45 + +The value is 27 and 55 + +The value is %0.8 +Simple printf +0xa +a +11 +011 +00000123 +56678 +00000000678123 +00012 +1.300000 +05.666600 ++678 ++0012 +{****678 ****} +****678 **** +The value is 17 and 2d + +The value is 2.300000e+00,6.780000,3.4 +4.53e+01 diff --git a/testsuite/test-fmt-cxpf/run.py b/testsuite/test-fmt-cxpf/run.py new file mode 100644 index 0000000000..06bf2a45d8 --- /dev/null +++ b/testsuite/test-fmt-cxpf/run.py @@ -0,0 +1,7 @@ +# Copyright Contributors to the Open Shading Language project. +# SPDX-License-Identifier: BSD-3-Clause +# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +command = "echo printf:>> out.txt 2>&1 ;\n" +command += testshade("-t 1 -g 2 2 -od uint8 -o Cout test_cxpf.tif test_cxpf") + diff --git a/testsuite/test-fmt-cxpf/test_cxpf.osl b/testsuite/test-fmt-cxpf/test_cxpf.osl new file mode 100644 index 0000000000..a021d360b7 --- /dev/null +++ b/testsuite/test-fmt-cxpf/test_cxpf.osl @@ -0,0 +1,101 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + + +struct Astruct { + int int1; + int int2; +}; + +shader test_cxpf (output float Cout = 0.0) +{ + + +printf("The values at %1.2f and %f are %d, %f, %f, %f, %f\n\n", 2.3434, 7.8, 5, 6.4, 123.456, 8.3232, 7.99999); + +printf("The value is %s\n", "spam"); //crashes for %s +printf("The value is %s \t \t and\t %d \n","fish", 12 ); //Produces a new line + + +//Print unmatched braces +printf("Give me unmatched braces {{{\n"); + +//Even number of braces with arguments +printf("The value is %d and {{%d}}\n", 3,67); + +// /NNN for unicode +printf("\124\105\101 time is %f PM\n", 4.09333); + + +color const_color = color(0.45, 0.37, .8); +color int_color = color(0,0,1); +color v_color = color(P[0]/3.4, P[1]/6.2, P[0]/2.2); + +int arr_col[3] = {0, 0, 1}; + +printf("Int arr_col[3]: %d\n", arr_col); +printf("Float color(): %f\n", const_color); +printf("Int color() only printable as floats: %f\n", int_color); +printf("Varying float color(): %f\n", v_color); + + + +Astruct a; +a.int1 = 12; +a.int2 = 42; + +printf("Int struct: a.int1: %d\n", a.int1); +printf("Int struct: a.int2: %d\n", a.int2); + +printf("The value is %3.4f and %g\n",4.569999945, 23.4); +printf("The value is %d and %f at ranges %f and %f\n\n", 12, 19.45, 3.4, 5.4); +printf("printf():The value is %0.8f and %0.3f\n\n", 1.23232, 19.45333); +printf("The value is %f\n\n", 2.3455); +printf("The value is %i and %i\n\n", 23, 45); +printf("The value is %o and %o\n\n", 23, 45); +printf("The value is %%0.8\n"); + +printf("Simple printf\n"); + +//flags: #, 0, +, - +//Hex +printf("%#x\n", 10); +printf("%x\n",10); + +//Octal +printf("%o\n",9); +printf("%#o\n", 9); + +//============================== +//Flag: 0 +//=============================== +printf("%08d\n",123); +printf("%01d\n",56678); + +printf("%014d\n",678123); +printf("%05d\n", 12); +printf("%02f\n",1.3); +printf("%09f\n", 5.6666); + +//============================ +//Flag: + +//=========================== + +printf("%+d\n",678); +printf("%+05d\n",12); + +//========================= +//Flag: - +//======================== +printf("{****%------4d****}\n",678); +printf("****%------4d****\n", 678); +printf("The value is %X and %x\n\n", 23, 45); +printf("The value is %e,%f,%g\n", 2.3, 6.78, 3.4); + +printf("%0.2e\n", 45.3232); + + +Cout = P[0] + P[1]; + +} diff --git a/testsuite/test-fmt-errorwarning-repeats/ref/out.txt b/testsuite/test-fmt-errorwarning-repeats/ref/out.txt new file mode 100644 index 0000000000..e6e6a58ecf --- /dev/null +++ b/testsuite/test-fmt-errorwarning-repeats/ref/out.txt @@ -0,0 +1,52 @@ +Compiled test_errorwarning.osl -> test_errorwarning.oso +errors and warnings with repeats: + +Output Cout to test_errorwarning.tif +ERROR: Shader error [test_errorwarning]: The weather is warm and rainy + +ERROR: Shader error [test_errorwarning]: The weather is warm and rainy + +WARNING: Shader warning [test_errorwarning]: Tsunami expected today + +ERROR: Shader error [test_errorwarning]: Volcano expected to erupt at 1300 hrs + +WARNING: Shader warning [test_errorwarning]: Flooding today + +WARNING: Shader warning [test_errorwarning]: Flooding today + +ERROR: Shader error [test_errorwarning]: The weather is warm and rainy + +ERROR: Shader error [test_errorwarning]: The weather is warm and rainy + +WARNING: Shader warning [test_errorwarning]: Tsunami expected today + +ERROR: Shader error [test_errorwarning]: Volcano expected to erupt at 1300 hrs + +WARNING: Shader warning [test_errorwarning]: Flooding today + +WARNING: Shader warning [test_errorwarning]: Flooding today + +ERROR: Shader error [test_errorwarning]: The weather is warm and rainy + +ERROR: Shader error [test_errorwarning]: The weather is warm and rainy + +WARNING: Shader warning [test_errorwarning]: Tsunami expected today + +ERROR: Shader error [test_errorwarning]: Volcano expected to erupt at 1300 hrs + +WARNING: Shader warning [test_errorwarning]: Flooding today + +WARNING: Shader warning [test_errorwarning]: Flooding today + +ERROR: Shader error [test_errorwarning]: The weather is warm and rainy + +ERROR: Shader error [test_errorwarning]: The weather is warm and rainy + +WARNING: Shader warning [test_errorwarning]: Tsunami expected today + +ERROR: Shader error [test_errorwarning]: Volcano expected to erupt at 1300 hrs + +WARNING: Shader warning [test_errorwarning]: Flooding today + +WARNING: Shader warning [test_errorwarning]: Flooding today + diff --git a/testsuite/test-fmt-errorwarning-repeats/run.py b/testsuite/test-fmt-errorwarning-repeats/run.py new file mode 100644 index 0000000000..0a3ca816df --- /dev/null +++ b/testsuite/test-fmt-errorwarning-repeats/run.py @@ -0,0 +1,7 @@ +# Copyright Contributors to the Open Shading Language project. +# SPDX-License-Identifier: BSD-3-Clause +# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +command = "echo errors and warnings with repeats:>> out.txt 2>&1 ;\n" +command += testshade("--options error_repeats=1 -t 1 -g 2 2 -od uint8 -o Cout test_errorwarning.tif test_errorwarning") + diff --git a/testsuite/test-fmt-errorwarning-repeats/test_errorwarning.osl b/testsuite/test-fmt-errorwarning-repeats/test_errorwarning.osl new file mode 100644 index 0000000000..fceb06a518 --- /dev/null +++ b/testsuite/test-fmt-errorwarning-repeats/test_errorwarning.osl @@ -0,0 +1,22 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + + +shader test_errorwarning (output float Cout = 0.0) +{ + + +//Duplicate errors +error("The weather is warm and rainy\n"); +error("The weather is warm and rainy\n"); + +warning("Tsunami expected today\n"); +error("Volcano expected to erupt at 1300 hrs\n"); + +warning("Flooding today\n"); +warning("Flooding today\n"); + +Cout = P[0] + P[1]; + +} diff --git a/testsuite/test-fmt-errorwarning/ref/out.txt b/testsuite/test-fmt-errorwarning/ref/out.txt new file mode 100644 index 0000000000..339754dc6f --- /dev/null +++ b/testsuite/test-fmt-errorwarning/ref/out.txt @@ -0,0 +1,12 @@ +Compiled test_errorwarning.osl -> test_errorwarning.oso +testing error warnings with no repeats: + +Output Cout to test_errorwarning.tif +ERROR: Shader error [test_errorwarning]: The weather is warm and rainy + +WARNING: Shader warning [test_errorwarning]: Tsunami expected today + +ERROR: Shader error [test_errorwarning]: Volcano expected to erupt at 1300 hrs + +WARNING: Shader warning [test_errorwarning]: Flooding today + diff --git a/testsuite/test-fmt-errorwarning/run.py b/testsuite/test-fmt-errorwarning/run.py new file mode 100644 index 0000000000..4c90a849bd --- /dev/null +++ b/testsuite/test-fmt-errorwarning/run.py @@ -0,0 +1,7 @@ +# Copyright Contributors to the Open Shading Language project. +# SPDX-License-Identifier: BSD-3-Clause +# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +command = "echo testing error warnings with no repeats:>> out.txt 2>&1 ;\n" +command += testshade("-t 1 -g 2 2 -od uint8 -o Cout test_errorwarning.tif test_errorwarning") + diff --git a/testsuite/test-fmt-errorwarning/test_errorwarning.osl b/testsuite/test-fmt-errorwarning/test_errorwarning.osl new file mode 100644 index 0000000000..fceb06a518 --- /dev/null +++ b/testsuite/test-fmt-errorwarning/test_errorwarning.osl @@ -0,0 +1,22 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + + +shader test_errorwarning (output float Cout = 0.0) +{ + + +//Duplicate errors +error("The weather is warm and rainy\n"); +error("The weather is warm and rainy\n"); + +warning("Tsunami expected today\n"); +error("Volcano expected to erupt at 1300 hrs\n"); + +warning("Flooding today\n"); +warning("Flooding today\n"); + +Cout = P[0] + P[1]; + +} diff --git a/testsuite/test-fmt-fileprint/ref/out.txt b/testsuite/test-fmt-fileprint/ref/out.txt new file mode 100644 index 0000000000..c9b770e105 --- /dev/null +++ b/testsuite/test-fmt-fileprint/ref/out.txt @@ -0,0 +1,2 @@ +Compiled test_fileprint.osl -> test_fileprint.oso + diff --git a/testsuite/test-fmt-fileprint/ref/out_fileprint.txt b/testsuite/test-fmt-fileprint/ref/out_fileprint.txt new file mode 100644 index 0000000000..da97ba9ac6 --- /dev/null +++ b/testsuite/test-fmt-fileprint/ref/out_fileprint.txt @@ -0,0 +1 @@ +pancakes{{{{{{}} and oatmeal diff --git a/testsuite/test-fmt-fileprint/run.py b/testsuite/test-fmt-fileprint/run.py new file mode 100644 index 0000000000..de7ee9d54f --- /dev/null +++ b/testsuite/test-fmt-fileprint/run.py @@ -0,0 +1,15 @@ +# Copyright Contributors to the Open Shading Language project. +# SPDX-License-Identifier: BSD-3-Clause +# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +from __future__ import absolute_import + +import os + +if os.path.isfile("out_fileprint.txt") : + os.remove ("out_fileprint.txt") + +command = testshade("test_fileprint") + +outputs = [ "out_fileprint.txt" ] + diff --git a/testsuite/test-fmt-fileprint/test_fileprint.osl b/testsuite/test-fmt-fileprint/test_fileprint.osl new file mode 100644 index 0000000000..18d8ba57db --- /dev/null +++ b/testsuite/test-fmt-fileprint/test_fileprint.osl @@ -0,0 +1,13 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + + +shader test_fileprint(output float Cout = 0.0) +{ + + +fprintf("out_fileprint.txt", "pancakes{{{{{{}} and oatmeal\n"); + + +} diff --git a/testsuite/test-fmt-journalbuffercapacity/run.py b/testsuite/test-fmt-journalbuffercapacity/run.py new file mode 100644 index 0000000000..ef89f33a1a --- /dev/null +++ b/testsuite/test-fmt-journalbuffercapacity/run.py @@ -0,0 +1,7 @@ +# Copyright Contributors to the Open Shading Language project. +# SPDX-License-Identifier: BSD-3-Clause +# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +command = "echo test warning when journal buffer capacity is inadequate>> out.txt 2>&1 ;\n" +command += testshade("--jbufferMB 3 -t 1 -g 64 64 -od uint8 -o Cout test_jbc.tif test_jbc") + diff --git a/testsuite/test-fmt-journalbuffercapacity/test_jbc.osl b/testsuite/test-fmt-journalbuffercapacity/test_jbc.osl new file mode 100644 index 0000000000..03419eacf6 --- /dev/null +++ b/testsuite/test-fmt-journalbuffercapacity/test_jbc.osl @@ -0,0 +1,99 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +struct Astruct { + int int1; + int int2; +}; + +shader test_jbc (output float Cout = 0.0) +{ + + +printf("The values at %1.2f and %f are %d, %f, %f, %f, %f\n\n", 2.3434, 7.8, 5, 6.4, 123.456, 8.3232, 7.99999); + +printf("The value is %s\n", "spam"); //crashes for %s +printf("The value is %s \t \t and\t %d \n","fish", 12 ); //Produces a new line + + +//Print unmatched braces +printf("Give me unmatched braces {{{\n"); + +//Even number of braces with arguments +printf("The value is %d and {{%d}}\n", 3,67); + +// /NNN for unicode +printf("\124\105\101 time is %f PM\n", 4.09333); + + +color const_color = color(0.45, 0.37, .8); +color int_color = color(0,0,1); //Compiler error: est_cxpf.osl:22: error: printf has mismatched format string and arguments (arg 2 needs %f, %g, or %e) +color v_color = color(P[0]/3.4, P[1]/6.2, P[0]/2.2); + +int arr_col[3] = {0, 0, 1}; + +printf("Int arr_col[3]: %d\n", arr_col); +printf("Float color(): %f\n", const_color); +printf("Int color() only printable as floats: %f\n", int_color); +printf("Varying float color(): %f\n", v_color); + + + +Astruct a; +a.int1 = 12; +a.int2 = 42; + +//printf("Int struct: a: %d\n", a); +printf("Int struct: a.int1: %d\n", a.int1); +printf("Int struct: a.int2: %d\n", a.int2); + +printf("The value is %3.4f and %g\n",4.569999945, 23.4);//Produces 4.5700 and 23.4 +printf("The value is %d and %f at ranges %f and %f\n\n", 12, 19.45, 3.4, 5.4); +printf("printf():The value is %0.8f and %0.3f\n\n", 1.23232, 19.45333); +printf("The value is %f\n\n", 2.3455); +printf("The value is %0.8i and %0.4i\n\n", 23, 45); +printf("The value is %0.8o and %0.4o\n\n", 23, 45); +printf("The value is %%0.8\n"); + +printf("Simple printf\n"); + +//flags: #, 0, +, - +//Hex +printf("%#x\n", 10); //0xa +printf("%x\n",10); //a + +//Octal +printf("%o\n",9);//11 +printf("%#o\n", 9);//011 + +//============================== +//Flag: 0 +//=============================== +printf("%08d\n",123); +printf("%01d\n",56678); + +printf("%014d\n",678123); +printf("%05d\n", 12); +printf("%02f\n",1.3); +printf("%09f\n", 5.6666); + +//============================ +//Flag: + +//=========================== + +printf("%+d\n",678); +printf("%+05d\n",12); + +//========================= +//Flag: - +//======================== + +printf("{****%-4d****}\n",678); + +printf("%0.2e\n", 45.3232); + + +Cout = P[0] + P[1]; + +} diff --git a/testsuite/test-fmt-matrixcolor/ref/out.txt b/testsuite/test-fmt-matrixcolor/ref/out.txt new file mode 100644 index 0000000000..830e3ca9a0 --- /dev/null +++ b/testsuite/test-fmt-matrixcolor/ref/out.txt @@ -0,0 +1,30 @@ +Compiled test_2wrongspaces.osl -> test_2wrongspaces.oso +Compiled test_const_matrixcolor.osl -> test_const_matrixcolor.oso +Compiled test_matrixcolor.osl -> test_matrixcolor.oso +incorrect color space and matrix transform names: + +Output Cout_color to matrixcolor1.tif +Output Cout_color1 to matrixcolor2.tif +Output Cout_matrix to matrixcolor3.tif +Output Cout_matrix1 to matrixcolor4.tif +ERROR: Unknown color space transformation "spam" -> "hsv" +ERROR: Unknown color space transformation "hsv" -> "spam" +ERROR: Unknown transformation "spam" +ERROR: Unknown transformation "water" +const-foldable version of incorrect color space and matrix transform names: + +Output Cout_color to const_matrixcolor1.tif +Output Cout_color1 to const_matrixcolor2.tif +Output Cout_matrix to const_matrixcolor3.tif +Output Cout_matrix1 to matrixcolor4.tif +ERROR: Unknown color space transformation "spam" -> "hsv" +ERROR: Unknown color space transformation "hsv" -> "spam" +ERROR: Unknown transformation "spam" +ERROR: Unknown transformation "water" +test_2wrongspaces.osl: + +Output Cout_color to matrixcolor1wrong.tif +Output Cout_matrix to matrixcolor2wrong.tif +ERROR: Unknown color space transformation "spam" -> "eggs" +ERROR: Unknown transformation "eggs" +ERROR: Unknown transformation "spam" diff --git a/testsuite/test-fmt-matrixcolor/run.py b/testsuite/test-fmt-matrixcolor/run.py new file mode 100644 index 0000000000..f26aa59188 --- /dev/null +++ b/testsuite/test-fmt-matrixcolor/run.py @@ -0,0 +1,11 @@ +# Copyright Contributors to the Open Shading Language project. +# SPDX-License-Identifier: BSD-3-Clause +# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +command = "echo incorrect color space and matrix transform names:>> out.txt 2>&1 ;\n" +command += testshade("-t 1 -g 2 2 -od uint8 -o Cout_color matrixcolor1.tif -o Cout_color1 matrixcolor2.tif -o Cout_matrix matrixcolor3.tif -o Cout_matrix1 matrixcolor4.tif test_matrixcolor") +command += "echo const-foldable version of incorrect color space and matrix transform names:>> out.txt 2>&1 ;\n" +command += testshade("-t 1 -g 2 2 -od uint8 -o Cout_color const_matrixcolor1.tif -o Cout_color1 const_matrixcolor2.tif -o Cout_matrix const_matrixcolor3.tif -o Cout_matrix1 matrixcolor4.tif test_const_matrixcolor") +command += "echo test_2wrongspaces.osl:>> out.txt 2>&1 ;\n" +command += testshade("-t 1 -g 2 2 -od uint8 -o Cout_color matrixcolor1wrong.tif -o Cout_matrix matrixcolor2wrong.tif test_2wrongspaces") + diff --git a/testsuite/test-fmt-matrixcolor/test_2wrongspaces.osl b/testsuite/test-fmt-matrixcolor/test_2wrongspaces.osl new file mode 100644 index 0000000000..f036759fa4 --- /dev/null +++ b/testsuite/test-fmt-matrixcolor/test_2wrongspaces.osl @@ -0,0 +1,23 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +//Errors in transform and transformc +shader +test_2wrongspaces ( + output color Cout_color = 0, + output color Cout_matrix = 0) +{ + + color uv = color (u, v, 0.5); + Cout_color = transformc("spam"/*from*/,"eggs"/*to*/,uv); + + matrix m1 = matrix(0); + getmatrix("eggs", "spam", m1); + + + Cout_matrix = color(m1[0][0] + m1[0][1] + m1[0][2] + m1[0][3], + m1[1][0] + m1[1][1] + m1[1][2] + m1[1][3], + m1[2][0] + m1[2][1] + m1[2][2] + m1[2][3] + + m1[3][0] + m1[3][1] + m1[3][2] + m1[3][3]); +} diff --git a/testsuite/test-fmt-matrixcolor/test_const_matrixcolor.osl b/testsuite/test-fmt-matrixcolor/test_const_matrixcolor.osl new file mode 100644 index 0000000000..3bc5ada231 --- /dev/null +++ b/testsuite/test-fmt-matrixcolor/test_const_matrixcolor.osl @@ -0,0 +1,38 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +//Errors in transform and transformc +shader +test_const_matrixcolor ( + output color Cout_color = 0, + output color Cout_matrix = 0, + output color Cout_color1 = 0, + output color Cout_matrix1 = 0) +{ + + color uv = color (0.3, 0.2, 0.5); + Cout_color = transformc("spam"/*from*/,"hsv"/*to*/,uv); + + Cout_color1 = transformc("hsv", "spam", uv); + + matrix m1 = matrix(0); + getmatrix("object", "spam", m1); + + matrix m11 = matrix(0); + getmatrix("water", "object", m11); //Error will not get printed if unknown transform space on two consecutive calls. + + + Cout_matrix = color(m1[0][0] + m1[0][1] + m1[0][2] + m1[0][3], + m1[1][0] + m1[1][1] + m1[1][2] + m1[1][3], + m1[2][0] + m1[2][1] + m1[2][2] + m1[2][3] + + m1[3][0] + m1[3][1] + m1[3][2] + m1[3][3]); + + + Cout_matrix1 = color(m11[0][0] + m11[0][1] + m11[0][2] + m11[0][3], + m11[1][0] + m11[1][1] + m11[1][2] + m11[1][3], + m11[2][0] + m11[2][1] + m11[2][2] + m11[2][3] + + m11[3][0] + m11[3][1] + m11[3][2] + m11[3][3]); + + +} diff --git a/testsuite/test-fmt-matrixcolor/test_matrixcolor.osl b/testsuite/test-fmt-matrixcolor/test_matrixcolor.osl new file mode 100644 index 0000000000..ce7dc63bb2 --- /dev/null +++ b/testsuite/test-fmt-matrixcolor/test_matrixcolor.osl @@ -0,0 +1,38 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +//Errors in transform and transformc +shader +test_matrixcolor ( + output color Cout_color = 0, + output color Cout_matrix = 0, + output color Cout_color1 = 0, + output color Cout_matrix1 = 0) +{ + + color uv = color (u, v, 0.5); + Cout_color = transformc("spam"/*from*/,"hsv"/*to*/,uv); + + Cout_color1 = transformc("hsv", "spam", uv); + + matrix m1 = matrix(0); + getmatrix("object", "spam", m1); + + matrix m11 = matrix(0); + getmatrix("water", "object", m11); //Error will not get printed if unknown transform space on two consecutive calls. + + + Cout_matrix = color(m1[0][0] + m1[0][1] + m1[0][2] + m1[0][3], + m1[1][0] + m1[1][1] + m1[1][2] + m1[1][3], + m1[2][0] + m1[2][1] + m1[2][2] + m1[2][3] + + m1[3][0] + m1[3][1] + m1[3][2] + m1[3][3]); + + + Cout_matrix1 = color(m11[0][0] + m11[0][1] + m11[0][2] + m11[0][3], + m11[1][0] + m11[1][1] + m11[1][2] + m11[1][3], + m11[2][0] + m11[2][1] + m11[2][2] + m11[2][3] + + m11[3][0] + m11[3][1] + m11[3][2] + m11[3][3]); + + +} diff --git a/testsuite/test-fmt-noise/ref/out.txt b/testsuite/test-fmt-noise/ref/out.txt new file mode 100644 index 0000000000..2348d6c5bb --- /dev/null +++ b/testsuite/test-fmt-noise/ref/out.txt @@ -0,0 +1,5 @@ +Compiled test_noise.osl -> test_noise.oso +incorrect noisetype: + +Output Cout to test_noise.tif +ERROR: noise type "spam" is unknown, called from (test_noise.osl:8) diff --git a/testsuite/test-fmt-noise/run.py b/testsuite/test-fmt-noise/run.py new file mode 100644 index 0000000000..b44915ff4f --- /dev/null +++ b/testsuite/test-fmt-noise/run.py @@ -0,0 +1,7 @@ +# Copyright Contributors to the Open Shading Language project. +# SPDX-License-Identifier: BSD-3-Clause +# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +command = "echo incorrect noisetype:>> out.txt 2>&1 ;\n" +command += testshade("-t 1 -g 2 2 -od uint8 -o Cout test_noise.tif test_noise") + diff --git a/testsuite/test-fmt-noise/test_noise.osl b/testsuite/test-fmt-noise/test_noise.osl new file mode 100644 index 0000000000..e5145c5211 --- /dev/null +++ b/testsuite/test-fmt-noise/test_noise.osl @@ -0,0 +1,10 @@ +//Copyright Contributors to the Open Shading Language project. +//SPDX-License-Identifier: BSD-3-Clause +//https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +shader test_noise(output float Cout = 0) +{ + +Cout = noise("spam", P[0]); + +} diff --git a/testsuite/test-fmt-stpf/ref/out.txt b/testsuite/test-fmt-stpf/ref/out.txt new file mode 100644 index 0000000000..dabf9f276e --- /dev/null +++ b/testsuite/test-fmt-stpf/ref/out.txt @@ -0,0 +1,28 @@ +Compiled test_stpf.osl -> test_stpf.oso +printf: + +Output Cout to test_stpf.tif +kitten weekly toys count: 3 4 6 8 3 4 6 +kitten street address: 389 vine +kitten coloring: 0.400000 0.400000 0.600000 +kitten struct coloring: (R) = 0.400000 +kitten struct coloring: (G) = 0.400000 +kitten struct coloring: (B) = 0.600000 +kitten weekly toys count: 3 4 6 8 3 4 6 +kitten street address: 389 vine +kitten coloring: 0.400000 0.400000 0.600000 +kitten struct coloring: (R) = 0.400000 +kitten struct coloring: (G) = 0.400000 +kitten struct coloring: (B) = 0.600000 +kitten weekly toys count: 3 4 6 8 3 4 6 +kitten street address: 389 vine +kitten coloring: 0.400000 0.400000 0.600000 +kitten struct coloring: (R) = 0.400000 +kitten struct coloring: (G) = 0.400000 +kitten struct coloring: (B) = 0.600000 +kitten weekly toys count: 3 4 6 8 3 4 6 +kitten street address: 389 vine +kitten coloring: 0.400000 0.400000 0.600000 +kitten struct coloring: (R) = 0.400000 +kitten struct coloring: (G) = 0.400000 +kitten struct coloring: (B) = 0.600000 diff --git a/testsuite/test-fmt-stpf/run.py b/testsuite/test-fmt-stpf/run.py new file mode 100644 index 0000000000..4b8432ee58 --- /dev/null +++ b/testsuite/test-fmt-stpf/run.py @@ -0,0 +1,7 @@ +# Copyright Contributors to the Open Shading Language project. +# SPDX-License-Identifier: BSD-3-Clause +# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +command = "echo printf:>> out.txt 2>&1 ;\n" +command += testshade("-t 1 -g 2 2 -od uint8 -o Cout test_stpf.tif test_stpf") + diff --git a/testsuite/test-fmt-stpf/test_stpf.osl b/testsuite/test-fmt-stpf/test_stpf.osl new file mode 100644 index 0000000000..a20b83ecdf --- /dev/null +++ b/testsuite/test-fmt-stpf/test_stpf.osl @@ -0,0 +1,73 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + + +struct address +{ +string street; +int number; +}; + +struct coloring { + float r; + float g; + float b; +}; + + +struct kittens { + + string name; + int age; + color col; + coloring k_col; + address k_add; + float weight; + int weekly_toys_count [7]; +}; + + + +shader test_stpf (output color Cout = 0) +{ + + +// Construct a struct instance + kittens k1; + +// Structure assignment + k1.name = "chamomile"; + k1.age = 1; + +// Kitten coloring assignment + k1.k_col.r = 0.4; + k1.k_col.g = 0.4; + k1.k_col.b = 0.6; + + k1.col = color(.4,.4,0.6); + +//Kitten address assignment + + k1.k_add.street = "vine"; + k1.k_add.number = 389; + k1.weight = 7.8; + k1.weekly_toys_count[0] = 3; + k1.weekly_toys_count[1] = 4; + k1.weekly_toys_count[2] = 6; + k1.weekly_toys_count[3] = 8; + k1.weekly_toys_count[4] = 3; + k1.weekly_toys_count[5] = 4; + k1.weekly_toys_count[6] = 6; + + + +printf("kitten weekly toys count: %d \n", k1.weekly_toys_count); +printf("kitten street address: %d %s \n", k1.k_add.number, k1.k_add.street); +printf("kitten coloring: %f\n", k1.col); +printf("kitten struct coloring: (R) = %f\n", k1.k_col.r); +printf("kitten struct coloring: (G) = %f\n", k1.k_col.g); +printf("kitten struct coloring: (B) = %f\n", k1.k_col.b); + + +}