diff --git a/qrenderdoc/Code/pyrenderdoc/document_check.i b/qrenderdoc/Code/pyrenderdoc/document_check.i new file mode 100644 index 000000000..541837639 --- /dev/null +++ b/qrenderdoc/Code/pyrenderdoc/document_check.i @@ -0,0 +1,70 @@ +// this file is included from renderdoc.i, it's not a module in itself + +%header %{ + #include +%} + +%init %{ + // verify that docstrings aren't duplicated, which is a symptom of missing DOCUMENT() + // macros around newly added classes/members. + #if !defined(RELEASE) + static bool doc_checked = false; + + if(!doc_checked) + { + doc_checked = true; + + std::set docstrings; + for(size_t i=0; i < sizeof(swig_type_initial)/sizeof(swig_type_initial[0]); i++) + { + SwigPyClientData *typeinfo = (SwigPyClientData *)swig_type_initial[i]->clientdata; + + // opaque types have no typeinfo, skip these + if(!typeinfo) continue; + + PyTypeObject *typeobj = typeinfo->pytype; + + std::string typedoc = typeobj->tp_doc; + + auto result = docstrings.insert(typedoc); + + if(!result.second) + { + snprintf(convert_error, sizeof(convert_error)-1, "Duplicate docstring '%s' found on struct '%s' - are you missing a DOCUMENT()?", typedoc.c_str(), typeobj->tp_name); + RENDERDOC_LogMessage(LogType::Fatal, "QTRD", __FILE__, __LINE__, convert_error); + } + + PyMethodDef *method = typeobj->tp_methods; + + while(method->ml_doc) + { + std::string typedoc = method->ml_doc; + + size_t i = 0; + while(typedoc[i] == '\n') + i++; + + // skip the first line as it's autodoc generated + i = typedoc.find('\n', i); + if(i != std::string::npos) + { + while(typedoc[i] == '\n') + i++; + + typedoc.erase(0, i); + + result = docstrings.insert(typedoc); + + if(!result.second) + { + snprintf(convert_error, sizeof(convert_error)-1, "Duplicate docstring '%s' found on method '%s' - are you missing a DOCUMENT()?", typedoc.c_str(), method->ml_name); + RENDERDOC_LogMessage(LogType::Fatal, "QTRD", __FILE__, __LINE__, convert_error); + } + } + + method++; + } + } + } + #endif +%} diff --git a/qrenderdoc/Code/pyrenderdoc/pyconversion.h b/qrenderdoc/Code/pyrenderdoc/pyconversion.h index 8ae5ee8c1..d7308856f 100644 --- a/qrenderdoc/Code/pyrenderdoc/pyconversion.h +++ b/qrenderdoc/Code/pyrenderdoc/pyconversion.h @@ -879,3 +879,53 @@ funcType ConvertFunc(PyObject *self, const char *funcname, PyObject *func, bool return f.call(funcname, func, global_internal_handle, failflag); }; } + +namespace +{ +template ::value> +struct pointer_unwrap; + +template +struct pointer_unwrap +{ + static void tempset(T &ptr, T *tempobj) {} + static void tempalloc(T &ptr, unsigned char *tempmem) {} + static void tempdealloc(T &ptr) {} + static T &indirect(T &ptr) { return ptr; } +}; + +template +struct pointer_unwrap +{ + typedef typename std::remove_pointer::type U; + + static void tempset(U *&ptr, U *tempobj) { ptr = tempobj; } + static void tempalloc(U *&ptr, unsigned char *tempmem) { ptr = new(tempmem) U; } + static void tempdealloc(U *ptr) { ptr->~U(); } + static U &indirect(U *ptr) { return *ptr; } +}; +}; + +template +inline void tempalloc(T &ptr, unsigned char *tempmem) +{ + pointer_unwrap::tempalloc(ptr, tempmem); +} + +template +inline void tempset(T &ptr, U *tempobj) +{ + pointer_unwrap::tempset(ptr, tempobj); +} + +template +inline void tempdealloc(T ptr) +{ + pointer_unwrap::tempdealloc(ptr); +} + +template +inline typename std::remove_pointer::type &indirect(T &ptr) +{ + return pointer_unwrap::indirect(ptr); +} \ No newline at end of file diff --git a/qrenderdoc/Code/pyrenderdoc/pyconversion.i b/qrenderdoc/Code/pyrenderdoc/pyconversion.i new file mode 100644 index 000000000..5d21992fc --- /dev/null +++ b/qrenderdoc/Code/pyrenderdoc/pyconversion.i @@ -0,0 +1,95 @@ +// this file is included from renderdoc.i, it's not a module in itself + +%define SIMPLE_TYPEMAPS_VARIANT(BaseType, SimpleType) +%typemap(in, fragment="pyconvert") SimpleType (BaseType temp) { + tempset($1, &temp); + + int res = ConvertFromPy($input, indirect($1)); + if(!SWIG_IsOK(res)) + { + SWIG_exception_fail(SWIG_ArgError(res), "in method '$symname' argument $argnum of type '$1_basetype'"); + } +} + +%typemap(out, fragment="pyconvert") SimpleType { + $result = ConvertToPy(self, indirect($1)); +} +%enddef + +%define SIMPLE_TYPEMAPS(SimpleType) + +SIMPLE_TYPEMAPS_VARIANT(SimpleType, SimpleType) +SIMPLE_TYPEMAPS_VARIANT(SimpleType, SimpleType *) +SIMPLE_TYPEMAPS_VARIANT(SimpleType, SimpleType &) + +%enddef + +%define CONTAINER_TYPEMAPS_VARIANT(ContainerType) + +%typemap(in, fragment="pyconvert") ContainerType (unsigned char tempmem[32]) { + static_assert(sizeof(tempmem) >= sizeof(std::remove_pointer::type), "not enough temp space for $1_basetype"); + + if(!PyList_Check($input)) + { + SWIG_exception_fail(SWIG_TypeError, "in method '$symname' list expected for argument $argnum of type '$1_basetype'"); + } + + tempalloc($1, tempmem); + + int failIdx = 0; + int res = TypeConversion::type>::ConvertFromPy($input, indirect($1), &failIdx); + + if(!SWIG_IsOK(res)) + { + snprintf(convert_error, sizeof(convert_error)-1, "in method '$symname' argument $argnum of type '$1_basetype', decoding element %d", failIdx); + SWIG_exception_fail(SWIG_ArgError(res), convert_error); + } +} + +%typemap(freearg, fragment="pyconvert") ContainerType { + tempdealloc($1); +} + +%typemap(argout, fragment="pyconvert") ContainerType { + // empty the previous contents + if(PyDict_Check($input)) + { + PyDict_Clear($input); + } + else + { + Py_ssize_t sz = PySequence_Size($input); + if(sz > 0) + PySequence_DelSlice($input, 0, sz); + } + + // overwrite with array contents + int failIdx = 0; + PyObject *res = TypeConversion::type>::ConvertToPyInPlace(self, $input, indirect($1), &failIdx); + + if(!res) + { + snprintf(convert_error, sizeof(convert_error)-1, "in method '$symname' argument $argnum of type '$1_basetype', encoding element %d", failIdx); + SWIG_exception_fail(SWIG_ValueError, convert_error); + } +} + +%typemap(out, fragment="pyconvert") ContainerType { + int failIdx = 0; + $result = TypeConversion::type>::ConvertToPy(self, indirect($1), &failIdx); + if(!$result) + { + snprintf(convert_error, sizeof(convert_error)-1, "in method '$symname' returning type '$1_basetype', encoding element %d", failIdx); + SWIG_exception_fail(SWIG_ValueError, convert_error); + } +} + +%enddef + +%define CONTAINER_TYPEMAPS(ContainerType) + +CONTAINER_TYPEMAPS_VARIANT(ContainerType) +CONTAINER_TYPEMAPS_VARIANT(ContainerType *) +CONTAINER_TYPEMAPS_VARIANT(ContainerType &) + +%enddef \ No newline at end of file diff --git a/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i b/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i index d7b2bd126..f0a97965b 100644 --- a/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i @@ -11,17 +11,9 @@ SIMPLE_TYPEMAPS(QString) SIMPLE_TYPEMAPS(QDateTime) -CONTAINER_TYPEMAPS(QList &) -CONTAINER_TYPEMAPS(QList *) CONTAINER_TYPEMAPS(QList) -CONTAINER_TYPEMAPS(QStringList &) -CONTAINER_TYPEMAPS(QStringList *) CONTAINER_TYPEMAPS(QStringList) -CONTAINER_TYPEMAPS(QVector &) -CONTAINER_TYPEMAPS(QVector *) CONTAINER_TYPEMAPS(QVector) -CONTAINER_TYPEMAPS(QMap &) -CONTAINER_TYPEMAPS(QMap *) CONTAINER_TYPEMAPS(QMap) // pass QWidget objects to PySide diff --git a/qrenderdoc/Code/pyrenderdoc/renderdoc.i b/qrenderdoc/Code/pyrenderdoc/renderdoc.i index f3f3ce20e..ebe6eec5f 100644 --- a/qrenderdoc/Code/pyrenderdoc/renderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/renderdoc.i @@ -38,171 +38,11 @@ %#include "Code/pyrenderdoc/pyconversion.h" } -%fragment("tempalloc", "header") { - template::value> - struct pointer_unwrap; - - template - struct pointer_unwrap - { - static void tempset(T &ptr, T *tempobj) - { - } - - static void tempalloc(T &ptr, unsigned char *tempmem) - { - } - - static void tempdealloc(T &ptr) - { - } - - static T &indirect(T &ptr) - { - return ptr; - } - }; - - template - struct pointer_unwrap - { - typedef typename std::remove_pointer::type U; - - static void tempset(U *&ptr, U *tempobj) - { - ptr = tempobj; - } - - static void tempalloc(U *&ptr, unsigned char *tempmem) - { - ptr = new (tempmem) U; - } - - static void tempdealloc(U *ptr) - { - ptr->~U(); - } - - static U &indirect(U *ptr) - { - return *ptr; - } - }; - - template - void tempalloc(T &ptr, unsigned char *tempmem) - { - pointer_unwrap::tempalloc(ptr, tempmem); - } - - template - void tempset(T &ptr, U *tempobj) - { - pointer_unwrap::tempset(ptr, tempobj); - } - - template - void tempdealloc(T ptr) - { - pointer_unwrap::tempdealloc(ptr); - } - - template - typename std::remove_pointer::type &indirect(T &ptr) - { - return pointer_unwrap::indirect(ptr); - } -} - -%define SIMPLE_TYPEMAPS_VARIANT(BaseType, SimpleType) -%typemap(in, fragment="tempalloc,pyconvert") SimpleType (BaseType temp) { - tempset($1, &temp); - - int res = ConvertFromPy($input, indirect($1)); - if(!SWIG_IsOK(res)) - { - SWIG_exception_fail(SWIG_ArgError(res), "in method '$symname' argument $argnum of type '$1_basetype'"); - } -} - -%typemap(out, fragment="tempalloc,pyconvert") SimpleType { - $result = ConvertToPy(self, indirect($1)); -} -%enddef - -%define SIMPLE_TYPEMAPS(SimpleType) - -SIMPLE_TYPEMAPS_VARIANT(SimpleType, SimpleType) -SIMPLE_TYPEMAPS_VARIANT(SimpleType, SimpleType *) -SIMPLE_TYPEMAPS_VARIANT(SimpleType, SimpleType &) - -%enddef - -%define CONTAINER_TYPEMAPS(ContainerType) - -%typemap(in, fragment="tempalloc,pyconvert") ContainerType (unsigned char tempmem[32]) { - static_assert(sizeof(tempmem) >= sizeof(std::remove_pointer::type), "not enough temp space for $1_basetype"); - - if(!PyList_Check($input)) - { - SWIG_exception_fail(SWIG_TypeError, "in method '$symname' list expected for argument $argnum of type '$1_basetype'"); - } - - tempalloc($1, tempmem); - - int failIdx = 0; - int res = TypeConversion::type>::ConvertFromPy($input, indirect($1), &failIdx); - - if(!SWIG_IsOK(res)) - { - snprintf(convert_error, sizeof(convert_error)-1, "in method '$symname' argument $argnum of type '$1_basetype', decoding element %d", failIdx); - SWIG_exception_fail(SWIG_ArgError(res), convert_error); - } -} - -%typemap(freearg, fragment="tempalloc") ContainerType { - tempdealloc($1); -} - -%typemap(argout, fragment="tempalloc,pyconvert") ContainerType { - // empty the previous contents - if(PyDict_Check($input)) - { - PyDict_Clear($input); - } - else - { - Py_ssize_t sz = PySequence_Size($input); - if(sz > 0) - PySequence_DelSlice($input, 0, sz); - } - - // overwrite with array contents - int failIdx = 0; - PyObject *res = TypeConversion::type>::ConvertToPyInPlace(self, $input, indirect($1), &failIdx); - - if(!res) - { - snprintf(convert_error, sizeof(convert_error)-1, "in method '$symname' argument $argnum of type '$1_basetype', encoding element %d", failIdx); - SWIG_exception_fail(SWIG_ValueError, convert_error); - } -} - -%typemap(out, fragment="tempalloc,pyconvert") ContainerType { - int failIdx = 0; - $result = TypeConversion::type>::ConvertToPy(self, indirect($1), &failIdx); - if(!$result) - { - snprintf(convert_error, sizeof(convert_error)-1, "in method '$symname' returning type '$1_basetype', encoding element %d", failIdx); - SWIG_exception_fail(SWIG_ValueError, convert_error); - } -} - -%enddef +%include "pyconversion.i" SIMPLE_TYPEMAPS(rdctype::str) -CONTAINER_TYPEMAPS(rdctype::arr) +CONTAINER_TYPEMAPS(rdctype::array) %typemap(in, fragment="pyconvert") std::function { PyObject *func = $input; @@ -296,71 +136,4 @@ void HandleCallbackFailure(PyObject *global_handle, bool &fail_flag) %} -%header %{ - #include -%} - -%init %{ - // verify that docstrings aren't duplicated, which is a symptom of missing DOCUMENT() - // macros around newly added classes/members. - #if !defined(RELEASE) - static bool doc_checked = false; - - if(!doc_checked) - { - doc_checked = true; - - std::set docstrings; - for(size_t i=0; i < sizeof(swig_type_initial)/sizeof(swig_type_initial[0]); i++) - { - SwigPyClientData *typeinfo = (SwigPyClientData *)swig_type_initial[i]->clientdata; - - // opaque types have no typeinfo, skip these - if(!typeinfo) continue; - - PyTypeObject *typeobj = typeinfo->pytype; - - std::string typedoc = typeobj->tp_doc; - - auto result = docstrings.insert(typedoc); - - if(!result.second) - { - snprintf(convert_error, sizeof(convert_error)-1, "Duplicate docstring '%s' found on struct '%s' - are you missing a DOCUMENT()?", typedoc.c_str(), typeobj->tp_name); - RENDERDOC_LogMessage(LogType::Fatal, "QTRD", __FILE__, __LINE__, convert_error); - } - - PyMethodDef *method = typeobj->tp_methods; - - while(method->ml_doc) - { - std::string typedoc = method->ml_doc; - - size_t i = 0; - while(typedoc[i] == '\n') - i++; - - // skip the first line as it's autodoc generated - i = typedoc.find('\n', i); - if(i != std::string::npos) - { - while(typedoc[i] == '\n') - i++; - - typedoc.erase(0, i); - - result = docstrings.insert(typedoc); - - if(!result.second) - { - snprintf(convert_error, sizeof(convert_error)-1, "Duplicate docstring '%s' found on method '%s' - are you missing a DOCUMENT()?", typedoc.c_str(), method->ml_name); - RENDERDOC_LogMessage(LogType::Fatal, "QTRD", __FILE__, __LINE__, convert_error); - } - } - - method++; - } - } - } - #endif -%} +%include "document_check.i" diff --git a/qrenderdoc/qrenderdoc_local.vcxproj b/qrenderdoc/qrenderdoc_local.vcxproj index b5e5e49e6..081ede8f7 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj +++ b/qrenderdoc/qrenderdoc_local.vcxproj @@ -1374,7 +1374,9 @@ + + diff --git a/qrenderdoc/qrenderdoc_local.vcxproj.filters b/qrenderdoc/qrenderdoc_local.vcxproj.filters index 1939c2e7f..3f319adf6 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj.filters +++ b/qrenderdoc/qrenderdoc_local.vcxproj.filters @@ -1057,6 +1057,12 @@ Code\pyrenderdoc + + Code\pyrenderdoc + + + Code\pyrenderdoc +