%module(docstring="This is the API to RenderDoc's internals.") renderdoc %feature("autodoc", "0"); // 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 // use documentation for docstrings #define DOCUMENT(text) %feature("docstring") text // 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; // strip off the RENDERDOC_ namespace prefix, it's unnecessary %rename("%(strip:[RENDERDOC_])s") ""; %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); } %typemap(in, fragment="pyconvert") std::function { PyObject *func = $input; failed$argnum = false; $1 = ConvertFunc<$1_ltype>("$symname", func, failed$argnum); } %typemap(argout) std::function (bool failed) { if(failed) SWIG_fail; } // 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); } %} %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 %}