diff --git a/qrenderdoc/CMakeLists.txt b/qrenderdoc/CMakeLists.txt index cb959a9d4..883faac61 100644 --- a/qrenderdoc/CMakeLists.txt +++ b/qrenderdoc/CMakeLists.txt @@ -128,18 +128,31 @@ else() "DEFINES+=PYSIDE2_ENABLED=0\n") endif() -# generate the SWIG interface file -add_custom_command(OUTPUT renderdoc_python.cxx renderdoc.py - COMMAND ${CMAKE_BINARY_DIR}/bin/swig -v -Wextra -Werror -O -c++ -python -modern -modernargs -enumclass -fastunpack -py3 -builtin -I${CMAKE_SOURCE_DIR}/renderdoc/api/replay -outdir ${CMAKE_CURRENT_BINARY_DIR} -o ${CMAKE_CURRENT_BINARY_DIR}/renderdoc_python.cxx ${CMAKE_CURRENT_SOURCE_DIR}/Code/pyrenderdoc/renderdoc.i - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Code/pyrenderdoc/renderdoc.i - DEPENDS custom_swig - DEPENDS renderdoc) +# generate the SWIG interface files +set(swig_interfaces + Code/pyrenderdoc/renderdoc.i + Code/pyrenderdoc/qrenderdoc.i) -add_custom_command(OUTPUT renderdoc.py.c - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/include-bin renderdoc.py renderdoc.py.c - DEPENDS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/include-bin - DEPENDS renderdoc_python.cxx) +set(swig_output) + +foreach(in ${swig_interfaces}) + get_filename_component(swig_file ${in} NAME_WE) + + add_custom_command(OUTPUT ${swig_file}_python.cxx ${swig_file}.py + COMMAND ${CMAKE_BINARY_DIR}/bin/swig -v -Wextra -Werror -O -c++ -python -modern -modernargs -enumclass -fastunpack -py3 -builtin -I${CMAKE_CURRENT_SOURCE_DIR} -I${CMAKE_SOURCE_DIR}/renderdoc/api/replay -outdir ${CMAKE_CURRENT_BINARY_DIR} -o ${CMAKE_CURRENT_BINARY_DIR}/${swig_file}_python.cxx ${CMAKE_CURRENT_SOURCE_DIR}/${in} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${in} + DEPENDS custom_swig + DEPENDS renderdoc) + + add_custom_command(OUTPUT ${swig_file}.py.c + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/include-bin ${swig_file}.py ${swig_file}.py.c + DEPENDS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/include-bin + DEPENDS ${swig_file}_python.cxx) + + list(APPEND swig_output ${swig_file}_python.cxx) + list(APPEND swig_output ${swig_file}.py.c) +endforeach() # The case here is deliberately not matching the executable name # This means the custom command doesn't create this output file, @@ -149,8 +162,7 @@ add_custom_command(OUTPUT QRenderDoc COMMAND qmake "CMAKE_DIR=${CMAKE_BINARY_DIR}" ${CMAKE_CURRENT_SOURCE_DIR} COMMAND $(MAKE) DEPENDS RenderDoc.icns - DEPENDS renderdoc_python.cxx - DEPENDS renderdoc.py.c) + DEPENDS ${swig_output}) add_custom_target(build-qrenderdoc ALL DEPENDS QRenderDoc DEPENDS renderdoc) install (PROGRAMS ${CMAKE_BINARY_DIR}/bin/qrenderdoc DESTINATION bin) diff --git a/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp b/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp index c11b4f55d..8bf55c047 100644 --- a/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp +++ b/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp @@ -49,6 +49,8 @@ PyTypeObject **SbkPySide2_QtWidgetsTypes = NULL; // defined in SWIG-generated renderdoc_python.cpp extern "C" PyObject *PyInit__renderdoc(void); extern "C" PyObject *PassObjectToPython(const char *type, void *obj); +// this one is in qrenderdoc_python.cpp +extern "C" PyObject *PyInit__qrenderdoc(void); #ifdef WIN32 @@ -56,9 +58,9 @@ extern "C" PyObject *PassObjectToPython(const char *type, void *obj); #include #include "Resources/resource.h" -QByteArray GetWrapperModule() +QByteArray GetResourceContents(int resource) { - HRSRC res = FindResource(NULL, MAKEINTRESOURCE(renderdoc_py_module), MAKEINTRESOURCE(TYPE_EMBED)); + HRSRC res = FindResource(NULL, MAKEINTRESOURCE(resource), MAKEINTRESOURCE(TYPE_EMBED)); HGLOBAL data = LoadResource(NULL, res); if(!data) @@ -70,16 +72,17 @@ QByteArray GetWrapperModule() return QByteArray(resData, (int)resSize); } +#define GetWrapperModule(name) GetResourceContents(name##_py_module) + #else // Otherwise it's compiled in via include-bin which converts to a .c with extern array extern unsigned char renderdoc_py[]; extern unsigned int renderdoc_py_len; +extern unsigned char qrenderdoc_py[]; +extern unsigned int qrenderdoc_py_len; -QByteArray GetWrapperModule() -{ - return QByteArray((const char *)renderdoc_py, (int)renderdoc_py_len); -} +#define GetWrapperModule(name) QByteArray((const char *)name##_py, (int)name##_py_len); #endif @@ -198,6 +201,7 @@ void PythonContext::GlobalInit() } PyImport_AppendInittab("_renderdoc", &PyInit__renderdoc); + PyImport_AppendInittab("_qrenderdoc", &PyInit__qrenderdoc); Py_SetProgramName(program_name); @@ -205,17 +209,26 @@ void PythonContext::GlobalInit() PyEval_InitThreads(); - QByteArray module_src = GetWrapperModule(); + QByteArray renderdoc_py_src = GetWrapperModule(renderdoc); - if(module_src.isEmpty()) + if(renderdoc_py_src.isEmpty()) { qCritical() << "renderdoc.py wrapper is corrupt/empty. Check build configuration to ensure " "SWIG compiled properly with python support."; return; } + QByteArray qrenderdoc_py_src = GetWrapperModule(qrenderdoc); + + if(qrenderdoc_py_src.isEmpty()) + { + qCritical() << "qrenderdoc.py wrapper is corrupt/empty. Check build configuration to ensure " + "SWIG compiled properly with python support."; + return; + } + PyObject *renderdoc_py_compiled = - Py_CompileString(module_src.data(), "renderdoc.py", Py_file_input); + Py_CompileString(renderdoc_py_src.data(), "renderdoc.py", Py_file_input); if(!renderdoc_py_compiled) { @@ -223,6 +236,16 @@ void PythonContext::GlobalInit() return; } + PyObject *qrenderdoc_py_compiled = + Py_CompileString(qrenderdoc_py_src.data(), "qrenderdoc.py", Py_file_input); + + if(!qrenderdoc_py_compiled) + { + Py_DecRef(renderdoc_py_compiled); + qCritical() << "Failed to compile qrenderdoc.py wrapper, python will not be available"; + return; + } + OutputRedirectorType.tp_name = "renderdoc_output_redirector"; OutputRedirectorType.tp_basicsize = sizeof(OutputRedirector); OutputRedirectorType.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_FINALIZE; @@ -238,10 +261,13 @@ void PythonContext::GlobalInit() PyObject *main_module = PyImport_AddModule("__main__"); PyObject *rdoc_module = PyImport_ExecCodeModule("renderdoc", renderdoc_py_compiled); + PyObject *qrdoc_module = PyImport_ExecCodeModule("qrenderdoc", qrenderdoc_py_compiled); Py_XDECREF(renderdoc_py_compiled); + Py_XDECREF(qrenderdoc_py_compiled); PyModule_AddObject(main_module, "renderdoc", rdoc_module); + PyModule_AddObject(main_module, "qrenderdoc", qrdoc_module); main_dict = PyModule_GetDict(main_module); @@ -480,6 +506,7 @@ void PythonContext::setGlobal(const char *varName, const char *typeName, void *o PyGILState_STATE gil = PyGILState_Ensure(); + // we don't need separate functions for each module, as they share type info PyObject *obj = PassObjectToPython(typeName, object); int ret = -1; diff --git a/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i b/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i new file mode 100644 index 000000000..c0c4f5b6d --- /dev/null +++ b/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i @@ -0,0 +1,58 @@ +%module(docstring="This is the API to QRenderDoc's high-level UI panels and functionality.") qrenderdoc + +%feature("autodoc", "0"); + +// use documentation for docstrings +#define DOCUMENT(text) %feature("docstring") text + +// import the renderdoc interface that we depend on +%import "renderdoc.i" + +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) + +// ignore these functions as we don't map QVariantMap to/from python +%ignore EnvironmentModification::toJSON; +%ignore EnvironmentModification::fromJSON; + +// rename the interfaces to remove the I prefix +%rename("%(regex:/^I([A-Z].*)/\\1/)s", %$isclass) ""; + +%{ + #define ENABLE_QT_CONVERT + + #include + #include + #include + #include + #include + #include + + #include "datetime.h" + + #include "Code/Interface/QRDInterface.h" +%} + +%include + +%include "Code/Interface/QRDInterface.h" +%include "Code/Interface/CommonPipelineState.h" +%include "Code/Interface/PersistantConfig.h" +%include "Code/Interface/RemoteHost.h" + +%init %{ + PyDateTime_IMPORT; +%} diff --git a/qrenderdoc/Resources/qrenderdoc.rc b/qrenderdoc/Resources/qrenderdoc.rc index 9c48978c6..f479d9757 100644 --- a/qrenderdoc/Resources/qrenderdoc.rc +++ b/qrenderdoc/Resources/qrenderdoc.rc @@ -101,6 +101,7 @@ END // embed the renderdoc.py generated by SWIG renderdoc_py_module TYPE_EMBED RENDERDOC_PY_PATH +qrenderdoc_py_module TYPE_EMBED QRENDERDOC_PY_PATH ///////////////////////////////////////////////////////////////////////////// // diff --git a/qrenderdoc/Resources/resource.h b/qrenderdoc/Resources/resource.h index 2d71d82be..ef3961538 100644 --- a/qrenderdoc/Resources/resource.h +++ b/qrenderdoc/Resources/resource.h @@ -6,6 +6,7 @@ #define TYPE_EMBED 256 #define renderdoc_py_module 101 +#define qrenderdoc_py_module 102 // Next default values for new objects // diff --git a/qrenderdoc/qrenderdoc.pro b/qrenderdoc/qrenderdoc.pro index f832836d1..3e7ccada0 100644 --- a/qrenderdoc/qrenderdoc.pro +++ b/qrenderdoc/qrenderdoc.pro @@ -52,16 +52,18 @@ win32 { swig.name = SWIG ${QMAKE_FILE_IN} swig.input = SWIGSOURCES swig.output = ${QMAKE_FILE_BASE}_python.cxx - swig.commands = $$_PRO_FILE_PWD_/3rdparty/swig/swig.exe -v -Wextra -Werror -O -c++ -python -modern -modernargs -enumclass -fastunpack -py3 -builtin -I$$_PRO_FILE_PWD_/../renderdoc/api/replay -outdir . -o ${QMAKE_FILE_BASE}_python.cxx ${QMAKE_FILE_IN} + swig.commands = $$_PRO_FILE_PWD_/3rdparty/swig/swig.exe -v -Wextra -Werror -O -c++ -python -modern -modernargs -enumclass -fastunpack -py3 -builtin -I$$_PRO_FILE_PWD_ -I$$_PRO_FILE_PWD_/../renderdoc/api/replay -outdir . -o ${QMAKE_FILE_BASE}_python.cxx ${QMAKE_FILE_IN} swig.CONFIG += target_predeps swig.variable_out = GENERATED_SOURCES silent:swig.commands = @echo SWIG ${QMAKE_FILE_IN} && $$swig.commands QMAKE_EXTRA_COMPILERS += swig SWIGSOURCES += Code/pyrenderdoc/renderdoc.i + SWIGSOURCES += Code/pyrenderdoc/qrenderdoc.i - # Embed renderdoc.py + # Embed renderdoc.py and qrenderdoc.py RC_DEFINES = RENDERDOC_PY_PATH=renderdoc.py + RC_DEFINES += QRENDERDOC_PY_PATH=qrenderdoc.py # Include and link against python INCLUDEPATH += $$_PRO_FILE_PWD_/3rdparty/python/include @@ -112,6 +114,8 @@ win32 { # Add the SWIG files that were generated in cmake SOURCES += $$CMAKE_DIR/qrenderdoc/renderdoc_python.cxx SOURCES += $$CMAKE_DIR/qrenderdoc/renderdoc.py.c + SOURCES += $$CMAKE_DIR/qrenderdoc/qrenderdoc_python.cxx + SOURCES += $$CMAKE_DIR/qrenderdoc/qrenderdoc.py.c CONFIG += warn_off CONFIG += c++14 diff --git a/qrenderdoc/qrenderdoc_local.vcxproj b/qrenderdoc/qrenderdoc_local.vcxproj index c6468dbda..b5e5e49e6 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj +++ b/qrenderdoc/qrenderdoc_local.vcxproj @@ -689,6 +689,9 @@ 4127;4456;4459;4701;4244;4706;4101;%(DisableSpecificWarnings) + + 4127;4456;4459;4701;4244;4706;4101;%(DisableSpecificWarnings) + @@ -1178,6 +1181,14 @@ $(IntDir)generated\%(Filename).py;$(IntDir)generated\%(Filename)_python.cxx;%(Outputs) false + + Document + %(Fullpath);Code\Interface\QRDInterface.h;Code\Interface\CommonPipelineState.h;Code\Interface\PersistantConfig.h;Code\Interface\RemoteHost.h;$(IntDir)generated\renderdoc.py;%(AdditionalInputs) + $(ProjectDir)3rdparty\swig\swig.exe -v -Wextra -Werror -O -c++ -python -modern -modernargs -enumclass -fastunpack -py3 -builtin -I$(SolutionDir)renderdoc\api\replay -I$(ProjectDir) -outdir $(IntDir)generated -o $(IntDir)generated\%(Filename)_python.cxx %(FullPath) + Compiling SWIG interface + $(IntDir)generated\%(Filename).py;$(IntDir)generated\%(Filename)_python.cxx;%(Outputs) + false + %(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe;%(AdditionalInputs) $(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe %(Fullpath) -o $(IntDir)generated\ui_%(Filename).h @@ -1543,7 +1554,7 @@ - RENDERDOC_PY_PATH=$(IntDir)\generated\renderdoc.py;%(PreprocessorDefinitions) + RENDERDOC_PY_PATH=$(IntDir)\generated\renderdoc.py;QRENDERDOC_PY_PATH=$(IntDir)\generated\qrenderdoc.py;%(PreprocessorDefinitions) diff --git a/qrenderdoc/qrenderdoc_local.vcxproj.filters b/qrenderdoc/qrenderdoc_local.vcxproj.filters index 581703e07..1939c2e7f 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj.filters +++ b/qrenderdoc/qrenderdoc_local.vcxproj.filters @@ -558,6 +558,9 @@ Code\pyrenderdoc + + Generated Files + Generated Files @@ -1316,5 +1319,8 @@ Code\pyrenderdoc + + Code\pyrenderdoc + \ No newline at end of file