diff --git a/qrenderdoc/CMakeLists.txt b/qrenderdoc/CMakeLists.txt index 97fcd0f24..c2c0d7860 100644 --- a/qrenderdoc/CMakeLists.txt +++ b/qrenderdoc/CMakeLists.txt @@ -51,6 +51,30 @@ else() add_custom_command(OUTPUT RenderDoc.icns COMMAND touch RenderDoc.icns) endif() +# Make sure Python 3 is found +set(Python_ADDITIONAL_VERSIONS 3.4) +find_package(PythonLibs 3 REQUIRED) +find_package(PythonInterp 3 REQUIRED) +# we also need python3-config for swig +if(NOT EXISTS "${PYTHON_EXECUTABLE}-config") + message(FATAL_ERROR "We require python3-config to build swig, please install the python dev package for your system.") +endif() + +include(ExternalProject) + +# Need bison for swig +find_package(BISON) + +# Compile our custom SWIG that will do scoped/strong enum classes +ExternalProject_Add(custom_swig + # using an URL to a zip directly so we don't clone the history etc + URL https://github.com/baldurk/swig/archive/renderdoc-3.0.12.zip + BUILD_IN_SOURCE 1 + CONFIGURE_COMMAND ./autogen.sh > /dev/null 2>&1 + COMMAND CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} ./configure --with-pcre=yes --prefix=${CMAKE_BINARY_DIR} > /dev/null 2>&1 + BUILD_COMMAND $(MAKE) > /dev/null 2>&1 + INSTALL_COMMAND $(MAKE) install > /dev/null 2>&1) + # Output our configuration for qmake. We output this to a separate file so that # the user can then open the qrenderdoc.pro in qt creator and be able to build # with these configuration entries propagated for e.g. linking against libraries @@ -73,6 +97,20 @@ file(WRITE "RENDERDOC_VERSION=${RENDERDOC_VERSION}\n" "\n" "OSX_ICONFILE=${CMAKE_CURRENT_BINARY_DIR}/RenderDoc.icns\n") + +# 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) + +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) + # The case here is deliberately not matching the executable name # This means the custom command doesn't create this output file, # which causes CMake to rerun this target every time so that Qt @@ -80,7 +118,9 @@ file(WRITE add_custom_command(OUTPUT QRenderDoc COMMAND qmake "CMAKE_DIR=${CMAKE_BINARY_DIR}" ${CMAKE_CURRENT_SOURCE_DIR} COMMAND $(MAKE) - DEPENDS RenderDoc.icns) + DEPENDS RenderDoc.icns + DEPENDS renderdoc_python.cxx + DEPENDS renderdoc.py.c) 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/pyconversion.h b/qrenderdoc/Code/pyrenderdoc/pyconversion.h new file mode 100644 index 000000000..7b51e9ad9 --- /dev/null +++ b/qrenderdoc/Code/pyrenderdoc/pyconversion.h @@ -0,0 +1,348 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2017 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +#include + +// struct to allow partial specialisation for enums +template ::value> +struct TypeConversion +{ + static swig_type_info *GetTypeInfo() + { + static swig_type_info *cached_type_info = NULL; + + if(cached_type_info) + return cached_type_info; + + std::string baseTypeName = TypeName(); + baseTypeName += " *"; + cached_type_info = SWIG_TypeQuery(baseTypeName.c_str()); + + return cached_type_info; + } + + static int Convert(PyObject *in, T &out) + { + swig_type_info *type_info = GetTypeInfo(); + if(type_info == NULL) + return SWIG_ERROR; + + T *ptr = NULL; + int res = SWIG_ConvertPtr(in, (void **)&ptr, type_info, 0); + if(SWIG_IsOK(res)) + out = *ptr; + + return res; + } + + static PyObject *Convert(const T &in) + { + swig_type_info *type_info = GetTypeInfo(); + if(type_info == NULL) + return NULL; + + T *pyCopy = new T(in); + return SWIG_InternalNewPointerObj((void *)pyCopy, type_info, 0); + } +}; + +// specialisations for integers +template <> +struct TypeConversion +{ + static int Convert(PyObject *in, uint8_t &out) + { + if(!PyLong_Check(in)) + return SWIG_TypeError; + + uint32_t longval = PyLong_AsUnsignedLong(in); + + if(PyErr_Occurred() || longval > 0xff) + return SWIG_OverflowError; + + out = uint8_t(longval & 0xff); + + return SWIG_OK; + } + + static PyObject *Convert(const uint8_t &in) { return PyLong_FromUnsignedLong(in); } +}; + +template <> +struct TypeConversion +{ + static int Convert(PyObject *in, uint32_t &out) + { + if(!PyLong_Check(in)) + return SWIG_TypeError; + + out = PyLong_AsUnsignedLong(in); + + if(PyErr_Occurred()) + return SWIG_OverflowError; + + return SWIG_OK; + } + + static PyObject *Convert(const uint32_t &in) { return PyLong_FromUnsignedLong(in); } +}; + +template <> +struct TypeConversion +{ + static int Convert(PyObject *in, int32_t &out) + { + if(!PyLong_Check(in)) + return SWIG_TypeError; + + out = PyLong_AsLong(in); + + if(PyErr_Occurred()) + return SWIG_OverflowError; + + return SWIG_OK; + } + + static PyObject *Convert(const int32_t &in) { return PyLong_FromLong(in); } +}; + +template <> +struct TypeConversion +{ + static int Convert(PyObject *in, uint64_t &out) + { + if(!PyLong_Check(in)) + return SWIG_TypeError; + + out = PyLong_AsUnsignedLongLong(in); + + if(PyErr_Occurred()) + return SWIG_OverflowError; + + return SWIG_OK; + } + + static PyObject *Convert(const uint64_t &in) { return PyLong_FromUnsignedLongLong(in); } +}; + +// partial specialisation for enums, we just convert as their underlying type, +// whatever integer size that happens to be +template +struct TypeConversion +{ + typedef typename std::underlying_type::type etype; + + static int Convert(PyObject *in, T &out) + { + etype int_out = 0; + int ret = TypeConversion::Convert(in, int_out); + out = T(int_out); + return ret; + } + + static PyObject *Convert(const T &in) { return TypeConversion::Convert(etype(in)); } +}; + +// specialisation for pair +template +struct TypeConversion, false> +{ + static int Convert(PyObject *in, rdctype::pair &out) + { + if(!PyTuple_Check(in)) + return SWIG_TypeError; + + Py_ssize_t size = PyTuple_Size(in); + + if(size != 2) + return SWIG_TypeError; + + int ret = TypeConversion::Convert(PyTuple_GetItem(in, 0), out.first); + if(SWIG_IsOK(ret)) + ret = TypeConversion::Convert(PyTuple_GetItem(in, 1), out.second); + + return ret; + } + + static PyObject *Convert(const rdctype::pair &in) + { + PyObject *first = TypeConversion::Convert(in.first); + if(!first) + return NULL; + + PyObject *second = TypeConversion::Convert(in.second); + if(!second) + return NULL; + + PyObject *ret = PyTuple_New(2); + if(!ret) + return NULL; + + PyTuple_SetItem(ret, 0, first); + PyTuple_SetItem(ret, 1, second); + + return ret; + } +}; + +// specialisation for array +template +struct TypeConversion, false> +{ + // we add some extra parameters so the typemaps for array can use these to get + // nicer failure error messages out with the index that failed + static int Convert(PyObject *in, rdctype::array &out, int *failIdx) + { + if(!PyList_Check(in)) + return SWIG_TypeError; + + out.create((int)PyList_Size(in)); + + for(int i = 0; i < out.count; i++) + { + int ret = TypeConversion::Convert(PyList_GetItem(in, i), out.elems[i]); + if(!SWIG_IsOK(ret)) + { + if(failIdx) + *failIdx = i; + return ret; + } + } + + return SWIG_OK; + } + + static int Convert(PyObject *in, rdctype::array &out) { return Convert(in, out, NULL); } + static PyObject *ConvertList(PyObject *list, const rdctype::array &in, int *failIdx) + { + for(int i = 0; i < in.count; i++) + { + PyObject *elem = TypeConversion::Convert(in.elems[i]); + + if(elem) + { + PyList_Append(list, elem); + } + else + { + if(failIdx) + *failIdx = i; + + return NULL; + } + } + + return list; + } + + static PyObject *Convert(const rdctype::array &in, int *failIdx) + { + PyObject *list = PyList_New(0); + if(!list) + return NULL; + + PyObject *ret = ConvertList(list, in, failIdx); + + // if a failure happened, don't leak the list we created + if(!ret) + Py_XDECREF(list); + + return ret; + } + + static PyObject *Convert(const rdctype::array &in) { return Convert(in, NULL); } +}; + +// specialisation for string +SWIGINTERN int SWIG_AsCharPtrAndSize(PyObject *obj, char **cptr, size_t *psize, int *alloc); + +template <> +struct TypeConversion +{ + static swig_type_info *GetTypeInfo() + { + static swig_type_info *cached_type_info = NULL; + + if(cached_type_info) + return cached_type_info; + + cached_type_info = SWIG_TypeQuery("rdctype::str *"); + + return cached_type_info; + } + + static int Convert(PyObject *in, rdctype::str &out) + { + char *buf = NULL; + size_t size = 0; + int alloc = SWIG_OLDOBJ; + + if(SWIG_IsOK(SWIG_AsCharPtrAndSize(in, &buf, &size, &alloc))) + { + if(!buf) + return SWIG_NullReferenceError; + + out.count = (int)size - 1; + out.elems = (char *)out.allocate(size); + memcpy(out.elems, buf, size - 1); + out.elems[size] = 0; + + if(alloc == SWIG_NEWOBJ) + delete[] buf; + + return SWIG_OK; + } + + swig_type_info *type_info = GetTypeInfo(); + if(!type_info) + return SWIG_ERROR; + + rdctype::str *ptr = NULL; + int res = SWIG_ConvertPtr(in, (void **)&ptr, type_info, 0); + if(SWIG_IsOK(res)) + out = *ptr; + + return res; + } + + static PyObject *Convert(const rdctype::str &in) + { + return PyUnicode_FromStringAndSize(in.elems, in.count); + } +}; + +// free functions forward to struct +template +int Convert(PyObject *in, T &out) +{ + return TypeConversion::Convert(in, out); +} + +template +PyObject *Convert(const T &in) +{ + return TypeConversion::Convert(in); +} \ No newline at end of file diff --git a/qrenderdoc/Code/pyrenderdoc/renderdoc.i b/qrenderdoc/Code/pyrenderdoc/renderdoc.i new file mode 100644 index 000000000..5e5a66681 --- /dev/null +++ b/qrenderdoc/Code/pyrenderdoc/renderdoc.i @@ -0,0 +1,271 @@ +%module(docstring="This is the API to RenderDoc's internals.") renderdoc + +%feature("autodoc"); + +// just define linux platform to make sure things compile with no extra __declspec attributes +#define RENDERDOC_PLATFORM_LINUX + +// we don't need these for the interface, they just confuse things +#define NO_ENUM_CLASS_OPERATORS + +// ignore warning about base class rdctype::array methods in rdctype::str +#pragma SWIG nowarn=401 + +// ignore warning about redundant declaration of typedef (byte/bool32) +#pragma SWIG nowarn=322 + +// rename the interfaces to remove the I prefix +%rename("%(regex:/^I([A-Z].*)/\\1/)s", %$isclass) ""; + +// Since SWIG will inline all namespaces, and doesn't support nested structs, the namespaces +// for each pipeline state causes conflicts. We just fall back to a rename with _ as that's +// still acceptable/intuitive. + +%rename(D3D11_Layout) D3D11Pipe::Layout; +%rename(D3D11_VB) D3D11Pipe::VB; +%rename(D3D11_IB) D3D11Pipe::IB; +%rename(D3D11_IA) D3D11Pipe::IA; +%rename(D3D11_View) D3D11Pipe::View; +%rename(D3D11_Sampler) D3D11Pipe::Sampler; +%rename(D3D11_CBuffer) D3D11Pipe::CBuffer; +%rename(D3D11_Shader) D3D11Pipe::Shader; +%rename(D3D11_SOBind) D3D11Pipe::SOBind; +%rename(D3D11_SO) D3D11Pipe::SO; +%rename(D3D11_Viewport) D3D11Pipe::Viewport; +%rename(D3D11_Scissor) D3D11Pipe::Scissor; +%rename(D3D11_RasterizerState) D3D11Pipe::RasterizerState; +%rename(D3D11_Rasterizer) D3D11Pipe::Rasterizer; +%rename(D3D11_DepthStencilState) D3D11Pipe::DepthStencilState; +%rename(D3D11_StencilOp) D3D11Pipe::StencilOp; +%rename(D3D11_Blend) D3D11Pipe::Blend; +%rename(D3D11_BlendOp) D3D11Pipe::BlendOp; +%rename(D3D11_BlendState) D3D11Pipe::BlendState; +%rename(D3D11_OM) D3D11Pipe::OM; +%rename(D3D11_State) D3D11Pipe::State; + +%rename(GL_VertexAttribute) GLPipe::VertexAttribute; +%rename(GL_VB) GLPipe::VB; +%rename(GL_VertexInput) GLPipe::VertexInput; +%rename(GL_Shader) GLPipe::Shader; +%rename(GL_FixedVertexProcessing) GLPipe::FixedVertexProcessing; +%rename(GL_Texture) GLPipe::Texture; +%rename(GL_Sampler) GLPipe::Sampler; +%rename(GL_Buffer) GLPipe::Buffer; +%rename(GL_ImageLoadStore) GLPipe::ImageLoadStore; +%rename(GL_Feedback) GLPipe::Feedback; +%rename(GL_Viewport) GLPipe::Viewport; +%rename(GL_Scissor) GLPipe::Scissor; +%rename(GL_RasterizerState) GLPipe::RasterizerState; +%rename(GL_Rasterizer) GLPipe::Rasterizer; +%rename(GL_DepthState) GLPipe::DepthState; +%rename(GL_StencilOp) GLPipe::StencilOp; +%rename(GL_StencilState) GLPipe::StencilState; +%rename(GL_Attachment) GLPipe::Attachment; +%rename(GL_FBO) GLPipe::FBO; +%rename(GL_BlendOp) GLPipe::BlendOp; +%rename(GL_Blend) GLPipe::Blend; +%rename(GL_BlendState) GLPipe::BlendState; +%rename(GL_FrameBuffer) GLPipe::FrameBuffer; +%rename(GL_Hints) GLPipe::Hints; +%rename(GL_State) GLPipe::State; + +%rename(VK_BindingElement) VKPipe::BindingElement; +%rename(VK_DescriptorBinding) VKPipe::DescriptorBinding; +%rename(VK_DescriptorSet) VKPipe::DescriptorSet; +%rename(VK_Pipeline) VKPipe::Pipeline; +%rename(VK_IB) VKPipe::IB; +%rename(VK_InputAssembly) VKPipe::InputAssembly; +%rename(VK_VertexAttribute) VKPipe::VertexAttribute; +%rename(VK_VertexBinding) VKPipe::VertexBinding; +%rename(VK_VB) VKPipe::VB; +%rename(VK_VertexInput) VKPipe::VertexInput; +%rename(VK_SpecInfo) VKPipe::SpecInfo; +%rename(VK_Shader) VKPipe::Shader; +%rename(VK_Tessellation) VKPipe::Tessellation; +%rename(VK_Viewport) VKPipe::Viewport; +%rename(VK_Scissor) VKPipe::Scissor; +%rename(VK_ViewportScissor) VKPipe::ViewportScissor; +%rename(VK_ViewState) VKPipe::ViewState; +%rename(VK_Raster) VKPipe::Raster; +%rename(VK_MultiSample) VKPipe::MultiSample; +%rename(VK_BlendOp) VKPipe::BlendOp; +%rename(VK_Blend) VKPipe::Blend; +%rename(VK_ColorBlend) VKPipe::ColorBlend; +%rename(VK_StencilOp) VKPipe::StencilOp; +%rename(VK_DepthStencil) VKPipe::DepthStencil; +%rename(VK_RenderPass) VKPipe::RenderPass; +%rename(VK_Attachment) VKPipe::Attachment; +%rename(VK_Framebuffer) VKPipe::Framebuffer; +%rename(VK_RenderArea) VKPipe::RenderArea; +%rename(VK_CurrentPass) VKPipe::CurrentPass; +%rename(VK_ImageLayout) VKPipe::ImageLayout; +%rename(VK_ImageData) VKPipe::ImageData; +%rename(VK_State) VKPipe::State; + +%rename(D3D12_Layout) D3D12Pipe::Layout; +%rename(D3D12_VB) D3D12Pipe::VB; +%rename(D3D12_IB) D3D12Pipe::IB; +%rename(D3D12_IA) D3D12Pipe::IA; +%rename(D3D12_View) D3D12Pipe::View; +%rename(D3D12_Sampler) D3D12Pipe::Sampler; +%rename(D3D12_CBuffer) D3D12Pipe::CBuffer; +%rename(D3D12_RegisterSpace) D3D12Pipe::RegisterSpace; +%rename(D3D12_Shader) D3D12Pipe::Shader; +%rename(D3D12_SOBind) D3D12Pipe::SOBind; +%rename(D3D12_Streamout) D3D12Pipe::Streamout; +%rename(D3D12_Viewport) D3D12Pipe::Viewport; +%rename(D3D12_Scissor) D3D12Pipe::Scissor; +%rename(D3D12_RasterizerState) D3D12Pipe::RasterizerState; +%rename(D3D12_Rasterizer) D3D12Pipe::Rasterizer; +%rename(D3D12_StencilOp) D3D12Pipe::StencilOp; +%rename(D3D12_DepthStencilState) D3D12Pipe::DepthStencilState; +%rename(D3D12_BlendOp) D3D12Pipe::BlendOp; +%rename(D3D12_Blend) D3D12Pipe::Blend; +%rename(D3D12_BlendState) D3D12Pipe::BlendState; +%rename(D3D12_OM) D3D12Pipe::OM; +%rename(D3D12_ResourceState) D3D12Pipe::ResourceState; +%rename(D3D12_ResourceData) D3D12Pipe::ResourceData; +%rename(D3D12_State) D3D12Pipe::State; + +%fragment("pyconvert", "header") { + static char convert_error[1024] = {}; + + %#include "Code/pyrenderdoc/pyconversion.h" +} + +%fragment("tempalloc", "header") { + template + void tempalloc(T *&ptr, unsigned char *tempmem) + { + ptr = new (tempmem) T; + } +} + +%typemap(in, fragment="tempalloc,pyconvert") rdctype::array * (unsigned char tempmem[sizeof(void*)*2]) { + static_assert(sizeof(tempmem) >= sizeof(*$1), "sizeof rdctype::array isn't equal"); + + 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>::Convert($input, *$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) rdctype::array * { + $1->Delete(); +} + +%typemap(argout, fragment="pyconvert") rdctype::array * { + // empty the previous contents + Py_ssize_t sz = PyList_Size($input); + if(sz > 0) + PySequence_DelSlice($input, 0, sz); + + // overwrite with array contents + int failIdx = 0; + PyObject *res = TypeConversion::type>::ConvertList($input, *$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") rdctype::array * { + int failIdx = 0; + $result = TypeConversion::type>::Convert(*$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); + } +} + +%typemap(in, fragment="pyconvert") rdctype::str * { + $1 = new rdctype::str; + int res = Convert($input, *$1); + if(!SWIG_IsOK(res)) + { + SWIG_exception_fail(SWIG_ArgError(res), "in method '$symname' argument $argnum of type '$1_basetype'"); + } +} +%typemap(freearg) rdctype::str * { + delete $1; +} + +%typemap(in, fragment="pyconvert") rdctype::str { + int res = Convert($input, $1); + if(!SWIG_IsOK(res)) + { + SWIG_exception_fail(SWIG_ArgError(res), "in method '$symname' argument $argnum of type '$1_basetype'"); + } +} + +%typemap(out, fragment="pyconvert") rdctype::str * { + $result = Convert(*$1); +} + +%typemap(out, fragment="pyconvert") rdctype::str { + $result = Convert($1); +} + +// ignore some operators SWIG doesn't have to worry about +%ignore rdctype::array::operator=; +%ignore rdctype::array::operator[]; +%ignore rdctype::str::operator=; +%ignore rdctype::str::operator const char *; + +// SWIG generates destructor wrappers for these interfaces that we don't want +%ignore IReplayOutput::~IReplayOutput(); +%ignore IReplayRenderer::~IReplayRenderer(); +%ignore ITargetControl::~ITargetControl(); +%ignore IRemoteServer::~IRemoteServer(); + +%{ + #include "renderdoc_replay.h" +%} + +%include + +%include "renderdoc_replay.h" +%include "basic_types.h" +%include "capture_options.h" +%include "control_types.h" +%include "d3d11_pipestate.h" +%include "d3d12_pipestate.h" +%include "data_types.h" +%include "gl_pipestate.h" +%include "replay_enums.h" +%include "shader_types.h" +%include "vk_pipestate.h" + +// add a built-in __str__ function that will generate string representations in python +%extend rdctype::str { + const char *__str__() const { return $self->c_str(); } +}; + +// declare a function for passing external objects into python +%wrapper %{ + +PyObject *PassObjectToPython(const char *type, void *obj) +{ + swig_type_info *t = SWIG_TypeQuery(type); + if(t == NULL) + return NULL; + + return SWIG_InternalNewPointerObj(obj, t, 0); +} + +%} + diff --git a/qrenderdoc/Resources/qrenderdoc.rc b/qrenderdoc/Resources/qrenderdoc.rc index 5edcc02e1..9c48978c6 100644 --- a/qrenderdoc/Resources/qrenderdoc.rc +++ b/qrenderdoc/Resources/qrenderdoc.rc @@ -99,6 +99,8 @@ BEGIN END END +// embed the renderdoc.py generated by SWIG +renderdoc_py_module TYPE_EMBED RENDERDOC_PY_PATH ///////////////////////////////////////////////////////////////////////////// // diff --git a/qrenderdoc/Resources/resource.h b/qrenderdoc/Resources/resource.h index b97b0f28b..2d71d82be 100644 --- a/qrenderdoc/Resources/resource.h +++ b/qrenderdoc/Resources/resource.h @@ -4,6 +4,9 @@ // #include "version.h" +#define TYPE_EMBED 256 +#define renderdoc_py_module 101 + // Next default values for new objects // #ifdef APSTUDIO_INVOKED diff --git a/qrenderdoc/qrenderdoc.pro b/qrenderdoc/qrenderdoc.pro index ae92f55f2..11fba49b1 100644 --- a/qrenderdoc/qrenderdoc.pro +++ b/qrenderdoc/qrenderdoc.pro @@ -48,6 +48,21 @@ win32 { Release:DESTDIR = $$_PRO_FILE_PWD_/../x64/Release } + # Run SWIG here, since normally we run it from VS + 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.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 + + # Embed renderdoc.py + RC_DEFINES = RENDERDOC_PY_PATH=renderdoc.py + # Link against the core library LIBS += $$DESTDIR/renderdoc.lib @@ -73,6 +88,10 @@ win32 { LIBS += -lrenderdoc QMAKE_LFLAGS += '-Wl,-rpath,\'\$$ORIGIN\',-rpath,\'\$$ORIGIN/../lib\'' + # Add the SWIG files that were generated in cmake + SOURCES += $$CMAKE_DIR/qrenderdoc/renderdoc_python.cxx + SOURCES += $$CMAKE_DIR/qrenderdoc/renderdoc.py.c + CONFIG += warn_off CONFIG += c++11 QMAKE_CFLAGS_WARN_OFF -= -w diff --git a/qrenderdoc/qrenderdoc_local.vcxproj b/qrenderdoc/qrenderdoc_local.vcxproj index e5c59fa08..02ac2fac6 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj +++ b/qrenderdoc/qrenderdoc_local.vcxproj @@ -115,7 +115,7 @@ $(ProjectDir);$(IntDir)generated\;$(SolutionDir)\renderdoc\api\replay;3rdparty\qt\$(Platform)\include;3rdparty\qt\$(Platform)\include\QtWidgets;3rdparty\qt\$(Platform)\include\QtGui;3rdparty\qt\$(Platform)\include\QtCore;%(AdditionalIncludeDirectories) - /wd4718 /wd4127 /wd4714 /wd4100 /wd4512 -Zc:strictStrings -Zc:throwingNew -w34189 -w44996 -w44456 -w44457 %(AdditionalOptions) + /wd4718 /wd4127 /wd4714 /wd4100 /wd4512 -Zc:strictStrings -Zc:throwingNew -w34189 -w44996 -w44457 %(AdditionalOptions) false ProgramDatabase 4577;%(DisableSpecificWarnings) @@ -159,7 +159,7 @@ $(ProjectDir);$(IntDir)generated\;$(SolutionDir)\renderdoc\api\replay;3rdparty\qt\$(Platform)\include;3rdparty\qt\$(Platform)\include\QtWidgets;3rdparty\qt\$(Platform)\include\QtGui;3rdparty\qt\$(Platform)\include\QtCore;%(AdditionalIncludeDirectories) - /wd4718 /wd4127 /wd4714 /wd4100 /wd4512 -Zc:strictStrings -Zc:throwingNew -w34189 -w44996 -w44456 -w44457 %(AdditionalOptions) + /wd4718 /wd4127 /wd4714 /wd4100 /wd4512 -Zc:strictStrings -Zc:throwingNew -w34189 -w44996 -w44457 %(AdditionalOptions) false ProgramDatabase 4577;%(DisableSpecificWarnings) @@ -203,7 +203,7 @@ $(ProjectDir);$(IntDir)generated\;$(SolutionDir)\renderdoc\api\replay;3rdparty\qt\$(Platform)\include;3rdparty\qt\$(Platform)\include\QtWidgets;3rdparty\qt\$(Platform)\include\QtGui;3rdparty\qt\$(Platform)\include\QtCore;%(AdditionalIncludeDirectories) - /wd4718 /wd4127 /wd4714 /wd4100 /wd4512 -Zc:strictStrings -Zc:throwingNew -w34189 -w44996 -w44456 -w44457 %(AdditionalOptions) + /wd4718 /wd4127 /wd4714 /wd4100 /wd4512 -Zc:strictStrings -Zc:throwingNew -w34189 -w44996 -w44457 %(AdditionalOptions) false ProgramDatabase 4577;%(DisableSpecificWarnings) @@ -244,7 +244,7 @@ $(ProjectDir);$(IntDir)generated\;$(SolutionDir)\renderdoc\api\replay;3rdparty\qt\$(Platform)\include;3rdparty\qt\$(Platform)\include\QtWidgets;3rdparty\qt\$(Platform)\include\QtGui;3rdparty\qt\$(Platform)\include\QtCore;%(AdditionalIncludeDirectories) - /wd4718 /wd4127 /wd4714 /wd4100 /wd4512 -Zc:strictStrings -Zc:throwingNew -w34189 -w44996 -w44456 -w44457 %(AdditionalOptions) + /wd4718 /wd4127 /wd4714 /wd4100 /wd4512 -Zc:strictStrings -Zc:throwingNew -w34189 -w44996 -w44457 %(AdditionalOptions) false ProgramDatabase 4577;%(DisableSpecificWarnings) @@ -285,7 +285,7 @@ $(ProjectDir);$(IntDir)generated\;$(SolutionDir)\renderdoc\api\replay;3rdparty\qt\$(Platform)\include;3rdparty\qt\$(Platform)\include\QtWidgets;3rdparty\qt\$(Platform)\include\QtGui;3rdparty\qt\$(Platform)\include\QtCore;%(AdditionalIncludeDirectories) - /wd4718 /wd4127 /wd4714 /wd4100 /wd4512 -Zc:strictStrings -Zc:throwingNew -w34189 -w44996 -w44456 -w44457 %(AdditionalOptions) + /wd4718 /wd4127 /wd4714 /wd4100 /wd4512 -Zc:strictStrings -Zc:throwingNew -w34189 -w44996 -w44457 %(AdditionalOptions) false ProgramDatabase 4577;%(DisableSpecificWarnings) @@ -326,7 +326,7 @@ $(ProjectDir);$(IntDir)generated\;$(SolutionDir)\renderdoc\api\replay;3rdparty\qt\$(Platform)\include;3rdparty\qt\$(Platform)\include\QtWidgets;3rdparty\qt\$(Platform)\include\QtGui;3rdparty\qt\$(Platform)\include\QtCore;%(AdditionalIncludeDirectories) - /wd4718 /wd4127 /wd4714 /wd4100 /wd4512 -Zc:strictStrings -Zc:throwingNew -w34189 -w44996 -w44456 -w44457 %(AdditionalOptions) + /wd4718 /wd4127 /wd4714 /wd4100 /wd4512 -Zc:strictStrings -Zc:throwingNew -w34189 -w44996 -w44457 %(AdditionalOptions) false ProgramDatabase 4577;%(DisableSpecificWarnings) @@ -689,6 +689,9 @@ + + 4127;4456;4459;4701;4244;4706;4101;%(DisableSpecificWarnings) + @@ -1163,6 +1166,14 @@ + + Document + %(Fullpath);pyconversion.i;document_check.i;$(SolutionDir)renderdoc\api\replay\basic_types.h;$(SolutionDir)renderdoc\api\replay\capture_options.h;$(SolutionDir)renderdoc\api\replay\control_types.h;$(SolutionDir)renderdoc\api\replay\d3d11_pipestate.h;$(SolutionDir)renderdoc\api\replay\d3d12_pipestate.h;$(SolutionDir)renderdoc\api\replay\data_types.h;$(SolutionDir)renderdoc\api\replay\gl_pipestate.h;$(SolutionDir)renderdoc\api\replay\renderdoc_replay.h;$(SolutionDir)renderdoc\api\replay\replay_enums.h;$(SolutionDir)renderdoc\api\replay\shader_types.h;$(SolutionDir)renderdoc\api\replay\vk_pipestate.h;%(AdditionalInputs) + $(ProjectDir)3rdparty\swig\swig.exe -v -Wextra -Werror -O -c++ -python -modern -modernargs -enumclass -fastunpack -py3 -builtin -I$(SolutionDir)renderdoc\api\replay -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 @@ -1348,6 +1359,7 @@ + @@ -1466,7 +1478,9 @@ - + + RENDERDOC_PY_PATH=$(IntDir)\generated\renderdoc.py;%(PreprocessorDefinitions) + diff --git a/qrenderdoc/qrenderdoc_local.vcxproj.filters b/qrenderdoc/qrenderdoc_local.vcxproj.filters index 75c51edfd..8d5e84ec6 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj.filters +++ b/qrenderdoc/qrenderdoc_local.vcxproj.filters @@ -22,6 +22,9 @@ {96c62ca7-39e7-4fca-a6a4-c8e1c3e2a324} + + {c2e91ed4-8c04-4fdc-accf-8fed288f2cd8} + {897f728c-8a11-41c3-ba6f-75815d9e06db} @@ -540,6 +543,9 @@ Generated Files + + Generated Files + Windows\Dialogs @@ -1030,6 +1036,9 @@ Resources\Files + + Code\pyrenderdoc + @@ -1286,5 +1295,8 @@ Widgets\Extended + + Code\pyrenderdoc + \ No newline at end of file