From 21d5943d821d9e5a4960071605f770b6ea5125e5 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 26 Dec 2017 12:11:34 +0000 Subject: [PATCH] Remove dependency on Qt in qrenderdoc python module * The main addition here apart from some extra stubs is a new rdc type for date time objects. * Although the module doesn't do anything and is only used for docs reflection it is desirable to not have to link against Qt as this can cause problems when linking the module without unresolved symbols. --- .../Code/Interface/PersistantConfig.cpp | 22 ++ qrenderdoc/Code/Interface/PersistantConfig.h | 30 +- qrenderdoc/Code/Interface/QRDInterface.h | 13 +- .../Code/Interface/SPIRVDisassembler.cpp | 9 +- qrenderdoc/Code/pyrenderdoc/CMakeLists.txt | 30 +- qrenderdoc/Code/pyrenderdoc/PythonContext.cpp | 10 + qrenderdoc/Code/pyrenderdoc/pyconversion.h | 29 +- qrenderdoc/Code/pyrenderdoc/qrenderdoc.i | 41 +-- .../pyrenderdoc/qrenderdoc_module.vcxproj | 10 +- .../qrenderdoc_module.vcxproj.filters | 16 +- .../Code/pyrenderdoc/qrenderdoc_stub.cpp | 284 +++++++++++++-- qrenderdoc/Code/pyrenderdoc/qt_conversion.h | 323 ------------------ qrenderdoc/Code/pyrenderdoc/renderdoc.i | 13 +- qrenderdoc/Windows/MainWindow.cpp | 6 +- qrenderdoc/qrenderdoc_local.vcxproj | 1 - qrenderdoc/qrenderdoc_local.vcxproj.filters | 3 - renderdoc/api/replay/basic_types.h | 65 ++++ 17 files changed, 450 insertions(+), 455 deletions(-) delete mode 100644 qrenderdoc/Code/pyrenderdoc/qt_conversion.h diff --git a/qrenderdoc/Code/Interface/PersistantConfig.cpp b/qrenderdoc/Code/Interface/PersistantConfig.cpp index da0b01f99..03ffa9a46 100644 --- a/qrenderdoc/Code/Interface/PersistantConfig.cpp +++ b/qrenderdoc/Code/Interface/PersistantConfig.cpp @@ -179,6 +179,23 @@ void PersistantConfig::applyValues(const QVariantMap &values) RENAMED_SETTING(QDateTime, DegradedLog_LastUpdate, DegradedCapture_LastUpdate); } +int PersistantConfig::RemoteHostCount() +{ + return RemoteHosts.count(); +} + +RemoteHost *PersistantConfig::GetRemoteHost(int index) +{ + if(index < 0 || index >= RemoteHostCount()) + return NULL; + return RemoteHosts[index]; +} + +void PersistantConfig::AddRemoteHost(RemoteHost host) +{ + RemoteHosts.push_back(new RemoteHost(host)); +} + void PersistantConfig::AddAndroidHosts() { QMap oldHosts; @@ -402,6 +419,11 @@ BugReport::BugReport(const QVariant &var) unreadUpdates = map[lit("unreadUpdates")].toBool(); } +rdcstr BugReport::URL() const +{ + return lit(BUGREPORT_URL "/report/%1").arg(QString(reportId)); +} + BugReport::operator QVariant() const { QVariantMap map; diff --git a/qrenderdoc/Code/Interface/PersistantConfig.h b/qrenderdoc/Code/Interface/PersistantConfig.h index 3edb8cb2c..b99ae415a 100644 --- a/qrenderdoc/Code/Interface/PersistantConfig.h +++ b/qrenderdoc/Code/Interface/PersistantConfig.h @@ -62,7 +62,7 @@ struct SPIRVDisassembler :return: The disassembly, or an empty string if something went wrong. :rtype: ``str`` )"); - QString DisassembleShader(QWidget *window, const ShaderReflection *reflection) const; + rdcstr DisassembleShader(QWidget *window, const ShaderReflection *reflection) const; }; DECLARE_REFLECTION_STRUCT(SPIRVDisassembler); @@ -95,9 +95,9 @@ struct BugReport DOCUMENT("The private ID of the bug report."); rdcstr reportId; DOCUMENT("The original date when this bug was submitted."); - QDateTime submitDate; + rdcdatetime submitDate; DOCUMENT("The last date that we checked for updates."); - QDateTime checkDate; + rdcdatetime checkDate; DOCUMENT("Unread updates to the bug exist"); bool unreadUpdates = false; @@ -106,7 +106,7 @@ struct BugReport :return: The URL to the report. :rtype: ``str`` )"); - rdcstr URL() const { return lit(BUGREPORT_URL "/report/%1").arg(QString(reportId)); } + rdcstr URL() const; }; DECLARE_REFLECTION_STRUCT(BugReport); @@ -188,11 +188,11 @@ DECLARE_REFLECTION_STRUCT(BugReport); \ CONFIG_SETTING_VAL(public, QString, rdcstr, CheckUpdate_UpdateResponse, "") \ \ - CONFIG_SETTING_VAL(public, QDateTime, QDateTime, CheckUpdate_LastUpdate, \ - QDateTime(QDate(2012, 06, 27), QTime(0, 0, 0))) \ + CONFIG_SETTING_VAL(public, QDateTime, rdcdatetime, CheckUpdate_LastUpdate, \ + rdcdatetime(2012, 06, 27)) \ \ - CONFIG_SETTING_VAL(public, QDateTime, QDateTime, DegradedCapture_LastUpdate, \ - QDateTime(QDate(2015, 01, 01), QTime(0, 0, 0))) \ + CONFIG_SETTING_VAL(public, QDateTime, rdcdatetime, DegradedCapture_LastUpdate, \ + rdcdatetime(2015, 01, 01)) \ \ CONFIG_SETTING_VAL(public, bool, bool, Tips_HasSeenFirst, false) \ \ @@ -570,25 +570,20 @@ public: :return: The number of remote hosts. :rtype: ``int`` )"); - int RemoteHostCount() { return RemoteHosts.count(); } + int RemoteHostCount(); DOCUMENT(R"(Returns a given remote host at an index. :param int index: The index of the remote host to retrieve :return: The remote host specified, or ``None`` if an invalid index was passed :rtype: ``RemoteHost`` )"); - RemoteHost *GetRemoteHost(int index) - { - if(index < 0 || index >= RemoteHostCount()) - return NULL; - return RemoteHosts[index]; - } + RemoteHost *GetRemoteHost(int index); DOCUMENT(R"(Adds a new remote host. :param RemoteHost host: The remote host to add. R)"); - void AddRemoteHost(RemoteHost host) { RemoteHosts.push_back(new RemoteHost(host)); } + void AddRemoteHost(RemoteHost host); DOCUMENT("If configured, queries ``adb`` to add android hosts to :data:`RemoteHosts`."); void AddAndroidHosts(); @@ -657,8 +652,11 @@ sure the new style is applied, the application should be restarted. private: bool Deserialize(const rdcstr &filename); bool Serialize(const rdcstr &filename); + +#if !defined(SWIG_GENERATED) QVariantMap storeValues() const; void applyValues(const QVariantMap &values); +#endif rdcstr m_Filename; }; diff --git a/qrenderdoc/Code/Interface/QRDInterface.h b/qrenderdoc/Code/Interface/QRDInterface.h index 4900d2666..d62326f04 100644 --- a/qrenderdoc/Code/Interface/QRDInterface.h +++ b/qrenderdoc/Code/Interface/QRDInterface.h @@ -1,11 +1,9 @@ #pragma once -// take care before adding any more headers here, as they must be converted to python types. Any -// types in the RenderDoc core interface are already wrapped, and Qt types must either be manually -// converted directly to python, or interfaced with PySide, otherwise we get into the situation -// where pyside and SWIG have independent incompatible wrappers of Qt types -#include - +// don't add any Qt headers visible to SWIG, as we don't want a Qt dependency for the SWIG-generated +// qrenderdoc module. Instead we should use public RDC types for any public QRenderDoc headers, and +// define conversions to/from Qt types. See rdcstr / QString, rdcpair / QPair, and +// rdcdatetime / QDateTime. #include // For string literals - use either tr() for translated strings, lit() for untranslated strings, or @@ -35,7 +33,7 @@ class QWidget; // we only support QVariant as an 'internal' interface, it's not exposed to python. However we need // to use it in constructors/operators so conditionally compile it rather than split small structs // into interface/implementations -#if defined(SWIG) +#if defined(SWIG) || defined(SWIG_GENERATED) #define VARIANT_CAST(classname) @@ -52,6 +50,7 @@ class QWidget; // is not exposed to swig #define RENDERDOC_QT_COMPAT #include +#include #include #include #include diff --git a/qrenderdoc/Code/Interface/SPIRVDisassembler.cpp b/qrenderdoc/Code/Interface/SPIRVDisassembler.cpp index b35dfbe22..aa3ee4661 100644 --- a/qrenderdoc/Code/Interface/SPIRVDisassembler.cpp +++ b/qrenderdoc/Code/Interface/SPIRVDisassembler.cpp @@ -27,11 +27,10 @@ #include "Code/QRDUtils.h" #include "QRDInterface.h" -QString SPIRVDisassembler::DisassembleShader(QWidget *window, - const ShaderReflection *shaderDetails) const +rdcstr SPIRVDisassembler::DisassembleShader(QWidget *window, const ShaderReflection *shaderDetails) const { if(executable.isEmpty()) - return QString(); + return ""; QString spv_bin_file = QDir(QDir::tempPath()).absoluteFilePath(lit("spv_bin.spv")); @@ -48,7 +47,7 @@ QString SPIRVDisassembler::DisassembleShader(QWidget *window, window, QApplication::translate("SPIRVDisassembler", "Error writing temp file"), QApplication::translate("SPIRVDisassembler", "Couldn't write temporary SPIR-V file %1.") .arg(spv_bin_file)); - return QString(); + return ""; } if(!QString(args).contains(lit("{spv_bin}"))) @@ -58,7 +57,7 @@ QString SPIRVDisassembler::DisassembleShader(QWidget *window, QApplication::translate( "SPIRVDisassembler", "Please use {spv_bin} in the disassembler arguments to specify the input file.")); - return QString(); + return ""; } QString glsl; diff --git a/qrenderdoc/Code/pyrenderdoc/CMakeLists.txt b/qrenderdoc/Code/pyrenderdoc/CMakeLists.txt index b652431c6..33ec09532 100644 --- a/qrenderdoc/Code/pyrenderdoc/CMakeLists.txt +++ b/qrenderdoc/Code/pyrenderdoc/CMakeLists.txt @@ -5,21 +5,6 @@ else () set (CMAKE_CXX_STANDARD 14) endif () -# Fetch the include and libs parameters for Qt -execute_process( - COMMAND pkg-config --cflags Qt5Widgets Qt5Core Qt5Gui - OUTPUT_VARIABLE QT5_INCLUDE - OUTPUT_STRIP_TRAILING_WHITESPACE) - -execute_process( - COMMAND pkg-config --libs Qt5Widgets Qt5Core Qt5Gui - OUTPUT_VARIABLE QT5_LIBS - OUTPUT_STRIP_TRAILING_WHITESPACE) - -if(STATIC_QRENDERDOC) - set(QT5_LIBS "${QT5_LIBS} -lqtpcre") -endif() - # include paths for qrenderdoc, the internal renderdoc API, and Python set(MODULE_INCLUDES PRIVATE ${CMAKE_SOURCE_DIR}/qrenderdoc @@ -30,6 +15,8 @@ set(MODULE_INCLUDES set(MODULE_DEFINES PRIVATE -DRENDERDOC_PLATFORM_LINUX) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-warning-option -Wno-unused-private-field") + # Set up rpath to find librenderdoc.so set(CMAKE_SKIP_BUILD_RPATH TRUE) set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) @@ -52,26 +39,15 @@ target_link_libraries(_renderdoc PRIVATE renderdoc) add_library(_qrenderdoc SHARED ${CMAKE_BINARY_DIR}/qrenderdoc/renderdoc_python.cxx ${CMAKE_BINARY_DIR}/qrenderdoc/qrenderdoc_python.cxx - ../Interface/CommonPipelineState.cpp - ../Interface/PersistantConfig.cpp - ../Interface/QRDInterface.cpp - ../Interface/RemoteHost.cpp pyrenderdoc_stub.cpp qrenderdoc_stub.cpp) set_source_files_properties(${CMAKE_BINARY_DIR}/qrenderdoc/qrenderdoc_python.cxx PROPERTIES GENERATED TRUE) -# Add in Qt includes and libraries -set (CMAKE_CXX_FLAGS "${QT5_INCLUDE} ${CMAKE_CXX_FLAGS}") -set (CMAKE_SHARED_LINKER_FLAGS "${QT5_LIBS} ${CMAKE_SHARED_LINKER_FLAGS}") -set (MODULE_LIBRARIES - PRIVATE renderdoc - ${QT5_LIBS}) - target_compile_definitions(_qrenderdoc ${MODULE_DEFINES}) target_include_directories(_qrenderdoc ${MODULE_INCLUDES}) -target_link_libraries(_qrenderdoc ${MODULE_LIBRARIES}) +target_link_libraries(_qrenderdoc PRIVATE renderdoc) # Don't prefix with lib, python expects a bare .so. # Also rename to non-underscore due to this (We couldn't call the diff --git a/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp b/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp index 1631e08b9..d06712b88 100644 --- a/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp +++ b/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp @@ -917,3 +917,13 @@ extern "C" void SetThreadBlocking(PyObject *global_handle, bool block) if(redirector && redirector->context) return redirector->context->setThreadBlocking(block); } + +extern "C" QWidget *QWidgetFromPy(PyObject *widget) +{ + return PythonContext::QWidgetFromPy(widget); +} + +extern "C" PyObject *QWidgetToPy(QWidget *widget) +{ + return PythonContext::QWidgetToPy(widget); +} \ No newline at end of file diff --git a/qrenderdoc/Code/pyrenderdoc/pyconversion.h b/qrenderdoc/Code/pyrenderdoc/pyconversion.h index 15ecdc203..eedd5154a 100644 --- a/qrenderdoc/Code/pyrenderdoc/pyconversion.h +++ b/qrenderdoc/Code/pyrenderdoc/pyconversion.h @@ -305,6 +305,33 @@ struct TypeConversion } }; +// specialisation for datetime +template <> +struct TypeConversion +{ + static int ConvertFromPy(PyObject *in, rdcdatetime &out) + { + if(!PyDateTime_Check(in)) + return SWIG_TypeError; + + out.year = PyDateTime_GET_YEAR(in); + out.month = PyDateTime_GET_MONTH(in); + out.day = PyDateTime_GET_DAY(in); + out.hour = PyDateTime_DATE_GET_HOUR(in); + out.minute = PyDateTime_DATE_GET_MINUTE(in); + out.second = PyDateTime_DATE_GET_SECOND(in); + out.microsecond = PyDateTime_TIME_GET_MICROSECOND(in); + + return SWIG_OK; + } + + static PyObject *ConvertToPy(const rdcdatetime &in) + { + return PyDateTime_FromDateAndTime(in.year, in.month, in.day, in.hour, in.minute, in.second, + in.microsecond); + } +}; + // specialisation for pair template struct TypeConversion, false> @@ -555,8 +582,6 @@ struct TypeConversion } }; -#include "qt_conversion.h" - #include "structured_conversion.h" // free functions forward to struct diff --git a/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i b/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i index e3431c3ee..6f524e28f 100644 --- a/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/qrenderdoc.i @@ -9,24 +9,16 @@ #define DOCUMENT4(text1, text2, text3, text4) %feature("docstring") text1 text2 text3 text4 %begin %{ - #undef slots + + #define SWIG_GENERATED %} %{ - #define ENABLE_QT_CONVERT - #define RENDERDOC_QT_COMPAT - - #include - #include - #include - #include - #include - #include - #include - #include "datetime.h" - +%} +%init %{ + PyDateTime_IMPORT; %} %include "pyconversion.i" @@ -34,14 +26,18 @@ // import the renderdoc interface that we depend on %import "renderdoc.i" -SIMPLE_TYPEMAPS(QString) -SIMPLE_TYPEMAPS(QDateTime) - TEMPLATE_ARRAY_DECLARE(rdcarray); // pass QWidget objects to PySide +%{ + class QWidget; + + extern "C" QWidget *QWidgetFromPy(PyObject *widget); + extern "C" PyObject *QWidgetToPy(QWidget *widget); +%} + %typemap(in) QWidget * { - $1 = PythonContext::QWidgetFromPy($input); + $1 = QWidgetFromPy($input); if($input && !$1) { SWIG_exception_fail(SWIG_TypeError, "in method '$symname' QWidget expected for argument $argnum of type '$1_basetype'"); @@ -49,7 +45,7 @@ TEMPLATE_ARRAY_DECLARE(rdcarray); } %typemap(out) QWidget * { - $result = PythonContext::QWidgetToPy($1); + $result = QWidgetToPy($1); } // need to ignore the original function and add a helper that releases the python GIL while calling @@ -63,12 +59,11 @@ TEMPLATE_ARRAY_DECLARE(rdcarray); %rename("%(regex:/^I([A-Z].*)/\\1/)s", %$isclass) ""; %{ -#ifndef slots -#define slots -#endif - #include "Code/Interface/QRDInterface.h" - #include "Code/pyrenderdoc/PythonContext.h" + + #ifndef slots + #define slots + #endif %} %include diff --git a/qrenderdoc/Code/pyrenderdoc/qrenderdoc_module.vcxproj b/qrenderdoc/Code/pyrenderdoc/qrenderdoc_module.vcxproj index 0a5a23cd9..c3974d705 100644 --- a/qrenderdoc/Code/pyrenderdoc/qrenderdoc_module.vcxproj +++ b/qrenderdoc/Code/pyrenderdoc/qrenderdoc_module.vcxproj @@ -75,15 +75,15 @@ true true /wd4100 /wd4512 /wd4127 - $(ProjectDir)..\..\;..\..\3rdparty\python\include;$(SolutionDir)\renderdoc\api\replay;..\..\3rdparty\qt\$(Platform)\include;..\..\3rdparty\qt\$(Platform)\include\QtWidgets;..\..\3rdparty\qt\$(Platform)\include\QtGui;..\..\3rdparty\qt\$(Platform)\include\QtCore + $(ProjectDir)..\..\;..\..\3rdparty\python\include;$(SolutionDir)\renderdoc\api\replay 4714;%(DisableSpecificWarnings) Windows true Default - ..\..\3rdparty\python\$(Platform);..\..\3rdparty\qt\$(Platform)\lib;%(AdditionalLibraryDirectories) - python36.lib;Qt5Widgets.lib;Qt5Gui.lib;Qt5Core.lib;%(AdditionalDependencies) + ..\..\3rdparty\python\$(Platform);%(AdditionalLibraryDirectories) + python36.lib;%(AdditionalDependencies) true @@ -107,10 +107,6 @@ - - - - diff --git a/qrenderdoc/Code/pyrenderdoc/qrenderdoc_module.vcxproj.filters b/qrenderdoc/Code/pyrenderdoc/qrenderdoc_module.vcxproj.filters index 3b4b79ee3..a9fa02cf9 100644 --- a/qrenderdoc/Code/pyrenderdoc/qrenderdoc_module.vcxproj.filters +++ b/qrenderdoc/Code/pyrenderdoc/qrenderdoc_module.vcxproj.filters @@ -2,23 +2,13 @@ + - - - Interface - - - Interface - - - Interface - - - Interface - + + diff --git a/qrenderdoc/Code/pyrenderdoc/qrenderdoc_stub.cpp b/qrenderdoc/Code/pyrenderdoc/qrenderdoc_stub.cpp index 7f46c99d5..4a88c647e 100644 --- a/qrenderdoc/Code/pyrenderdoc/qrenderdoc_stub.cpp +++ b/qrenderdoc/Code/pyrenderdoc/qrenderdoc_stub.cpp @@ -23,47 +23,285 @@ ******************************************************************************/ #include -#include "Code/QRDUtils.h" -#include "Styles/StyleData.h" -#include "PythonContext.h" -namespace StyleData -{ -const ThemeDescriptor availStyles[] = { - ThemeDescriptor(QString(), QString(), QString(), []() -> QStyle * { return NULL; }), -}; -const int numAvailable = sizeof(availStyles) / sizeof(ThemeDescriptor); -}; +#define SWIG_GENERATED +#include "Code/Interface/QRDInterface.h" // we only support the qrenderdoc module for docs generation, so it doesn't matter that these stub // functions aren't valid -void Formatter::setParams(const PersistantConfig &config) +//////////////////////////////////////////////////////////////////////////////// +// QRDInterface.cpp stubs +//////////////////////////////////////////////////////////////////////////////// + +CaptureSettings::CaptureSettings() { + inject = false; + autoStart = false; + RENDERDOC_GetDefaultCaptureOptions(&options); } -bool SaveToJSON(QVariantMap &data, QIODevice &f, const char *magicIdentifier, uint32_t magicVersion) +rdcstr configFilePath(const rdcstr &filename) { - return false; + return ""; } -bool LoadFromJSON(QVariantMap &data, QIODevice &f, const char *magicIdentifier, uint32_t magicVersion) -{ - return false; -} - -QWidget *PythonContext::QWidgetFromPy(PyObject *widget) +ICaptureContext *getCaptureContext(const QWidget *widget) { return NULL; } -PyObject *PythonContext::QtObjectToPython(const char *typeName, QObject *object) +//////////////////////////////////////////////////////////////////////////////// +// PythonContext.cpp stubs +//////////////////////////////////////////////////////////////////////////////// + +class QWidget; + +extern "C" QWidget *QWidgetFromPy(PyObject *widget) { return NULL; } -QString SPIRVDisassembler::DisassembleShader(QWidget *window, - const ShaderReflection *shaderDetails) const +extern "C" PyObject *QWidgetToPy(QWidget *widget) { - return QString(); + Py_IncRef(Py_None); + return Py_None; +} + +//////////////////////////////////////////////////////////////////////////////// +// SPIRVDisassembler.cpp stubs +//////////////////////////////////////////////////////////////////////////////// + +rdcstr SPIRVDisassembler::DisassembleShader(QWidget *window, const ShaderReflection *shaderDetails) const +{ + return ""; +} + +//////////////////////////////////////////////////////////////////////////////// +// PersistantConfig.cpp stubs +//////////////////////////////////////////////////////////////////////////////// + +rdcstr BugReport::URL() const +{ + return ""; +} + +bool PersistantConfig::SetStyle() +{ + return false; +} + +PersistantConfig::~PersistantConfig() +{ +} + +bool PersistantConfig::Load(const rdcstr &filename) +{ + return false; +} + +bool PersistantConfig::Save() +{ + return false; +} + +void PersistantConfig::Close() +{ +} + +int PersistantConfig::RemoteHostCount() +{ + return 0; +} + +RemoteHost *PersistantConfig::GetRemoteHost(int index) +{ + return NULL; +} + +void PersistantConfig::AddRemoteHost(RemoteHost host) +{ +} + +void PersistantConfig::AddAndroidHosts() +{ +} + +void PersistantConfig::SetupFormatting() +{ +} + +void AddRecentFile(rdcarray &recentList, const rdcstr &file, int maxItems) +{ +} + +void PersistantConfig::SetConfigSetting(const rdcstr &name, const rdcstr &value) +{ +} + +rdcstr PersistantConfig::GetConfigSetting(const rdcstr &name) +{ + return ""; +} + +//////////////////////////////////////////////////////////////////////////////// +// RemoteHost.cpp stubs +//////////////////////////////////////////////////////////////////////////////// + +RemoteHost::RemoteHost() +{ + serverRunning = connected = busy = versionMismatch = false; +} + +void RemoteHost::CheckStatus() +{ +} + +void RemoteHost::Launch() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// CommonPipelineState.cpp stubs +//////////////////////////////////////////////////////////////////////////////// + +rdcstr CommonPipelineState::GetResourceLayout(ResourceId id) +{ + return ""; +} + +rdcstr CommonPipelineState::Abbrev(ShaderStage stage) +{ + return ""; +} + +rdcstr CommonPipelineState::OutputAbbrev() +{ + return ""; +} + +const D3D11Pipe::Shader &CommonPipelineState::GetD3D11Stage(ShaderStage stage) +{ + static D3D11Pipe::Shader dummy; + return dummy; +} + +const D3D12Pipe::Shader &CommonPipelineState::GetD3D12Stage(ShaderStage stage) +{ + static D3D12Pipe::Shader dummy; + return dummy; +} + +const GLPipe::Shader &CommonPipelineState::GetGLStage(ShaderStage stage) +{ + static GLPipe::Shader dummy; + return dummy; +} + +const VKPipe::Shader &CommonPipelineState::GetVulkanStage(ShaderStage stage) +{ + static VKPipe::Shader dummy; + return dummy; +} + +rdcstr CommonPipelineState::GetShaderExtension() +{ + return ""; +} + +Viewport CommonPipelineState::GetViewport(int index) +{ + return Viewport(); +} + +Scissor CommonPipelineState::GetScissor(int index) +{ + return Scissor(); +} + +const ShaderBindpointMapping &CommonPipelineState::GetBindpointMapping(ShaderStage stage) +{ + static ShaderBindpointMapping dummy; + return dummy; +} + +const ShaderReflection *CommonPipelineState::GetShaderReflection(ShaderStage stage) +{ + return NULL; +} + +ResourceId CommonPipelineState::GetComputePipelineObject() +{ + return ResourceId(); +} + +ResourceId CommonPipelineState::GetGraphicsPipelineObject() +{ + return ResourceId(); +} + +rdcstr CommonPipelineState::GetShaderEntryPoint(ShaderStage stage) +{ + return ""; +} + +ResourceId CommonPipelineState::GetShader(ShaderStage stage) +{ + return ResourceId(); +} + +rdcstr CommonPipelineState::GetShaderName(ShaderStage stage) +{ + return ""; +} + +BoundVBuffer CommonPipelineState::GetIBuffer() +{ + return BoundVBuffer(); +} + +bool CommonPipelineState::IsStripRestartEnabled() +{ + return false; +} + +uint32_t CommonPipelineState::GetStripRestartIndex() +{ + return UINT32_MAX; +} + +rdcarray CommonPipelineState::GetVBuffers() +{ + return rdcarray(); +} + +rdcarray CommonPipelineState::GetVertexInputs() +{ + return rdcarray(); +} + +BoundCBuffer CommonPipelineState::GetConstantBuffer(ShaderStage stage, uint32_t BufIdx, + uint32_t ArrayIdx) +{ + return BoundCBuffer(); +} + +rdcarray CommonPipelineState::GetReadOnlyResources(ShaderStage stage) +{ + return rdcarray(); +} + +rdcarray CommonPipelineState::GetReadWriteResources(ShaderStage stage) +{ + return rdcarray(); +} + +BoundResource CommonPipelineState::GetDepthTarget() +{ + return BoundResource(); +} + +rdcarray CommonPipelineState::GetOutputTargets() +{ + return rdcarray(); } diff --git a/qrenderdoc/Code/pyrenderdoc/qt_conversion.h b/qrenderdoc/Code/pyrenderdoc/qt_conversion.h deleted file mode 100644 index f295059ed..000000000 --- a/qrenderdoc/Code/pyrenderdoc/qt_conversion.h +++ /dev/null @@ -1,323 +0,0 @@ -/****************************************************************************** - * 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 - -#ifdef ENABLE_QT_CONVERT - -template <> -struct TypeConversion -{ - static int ConvertFromPy(PyObject *in, QString &out) - { - if(PyUnicode_Check(in)) - { - PyObject *bytes = PyUnicode_AsUTF8String(in); - - if(!bytes) - return SWIG_ERROR; - - char *buf = NULL; - Py_ssize_t size = 0; - - int ret = PyBytes_AsStringAndSize(bytes, &buf, &size); - - if(ret == 0) - { - out = QString::fromUtf8(buf, (int)size); - - Py_DecRef(bytes); - - return SWIG_OK; - } - - Py_DecRef(bytes); - - return SWIG_ERROR; - } - - return SWIG_ERROR; - } - - static PyObject *ConvertToPy(const QString &in) - { - QByteArray bytes = in.toUtf8(); - return PyUnicode_FromStringAndSize(bytes.data(), bytes.size()); - } -}; - -template <> -struct TypeConversion -{ - static int ConvertFromPy(PyObject *in, QDateTime &out) - { - if(!PyDateTime_Check(in)) - return SWIG_TypeError; - - QDate date(PyDateTime_GET_YEAR(in), PyDateTime_GET_MONTH(in), PyDateTime_GET_DAY(in)); - QTime time(PyDateTime_DATE_GET_HOUR(in), PyDateTime_DATE_GET_MINUTE(in), - PyDateTime_DATE_GET_SECOND(in), PyDateTime_DATE_GET_MICROSECOND(in) / 1000); - - out = QDateTime(date, time, QTimeZone::utc()); - - return SWIG_OK; - } - - static PyObject *ConvertToPy(const QDateTime &in) - { - QDate date = in.date(); - QTime time = in.time(); - return PyDateTime_FromDateAndTime(date.year(), date.month(), date.day(), time.hour(), - time.minute(), time.second(), time.msec() * 1000); - } -}; - -template -struct ContainerConversion -{ - // 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 ConvertFromPy(PyObject *in, Container &out, int *failIdx) - { - if(!PyList_Check(in)) - return SWIG_TypeError; - - Py_ssize_t len = PyList_Size(in); - - for(Py_ssize_t i = 0; i < len; i++) - { - U u; - int ret = TypeConversion::ConvertFromPy(PyList_GetItem(in, i), u); - if(!SWIG_IsOK(ret)) - { - if(failIdx) - *failIdx = i; - return ret; - } - out.append(u); - } - - return SWIG_OK; - } - - static int ConvertFromPy(PyObject *in, Container &out) { return ConvertFromPy(in, out, NULL); } - static PyObject *ConvertToPyInPlace(PyObject *list, const Container &in, int *failIdx) - { - for(int i = 0; i < in.size(); i++) - { - PyObject *elem = TypeConversion::ConvertToPy(in[i]); - - if(elem) - { - PyList_Append(list, elem); - // release our reference - Py_DecRef(elem); - } - else - { - if(failIdx) - *failIdx = i; - - return NULL; - } - } - - return list; - } - - static PyObject *ConvertToPy(const Container &in, int *failIdx) - { - PyObject *list = PyList_New(0); - if(!list) - return NULL; - - PyObject *ret = ConvertToPyInPlace(list, in, failIdx); - - // if a failure happened, don't leak the list we created - if(!ret) - Py_XDECREF(list); - - return ret; - } - - static PyObject *ConvertToPy(const Container &in) { return ConvertToPy(in, NULL); } -}; - -template -struct TypeConversion, false> : ContainerConversion, U> -{ -}; - -template <> -struct TypeConversion : ContainerConversion, QString> -{ -}; - -template -struct TypeConversion, false> : ContainerConversion, U> -{ -}; - -// specialisation for pair -template -struct TypeConversion, false> -{ - static int ConvertFromPy(PyObject *in, QPair &out) - { - if(!PyTuple_Check(in)) - return SWIG_TypeError; - - Py_ssize_t size = PyTuple_Size(in); - - if(size != 2) - return SWIG_TypeError; - - int ret = TypeConversion::ConvertFromPy(PyTuple_GetItem(in, 0), out.first); - if(SWIG_IsOK(ret)) - ret = TypeConversion::ConvertFromPy(PyTuple_GetItem(in, 1), out.second); - - return ret; - } - - static PyObject *ConvertToPy(const QPair &in) - { - PyObject *first = TypeConversion::ConvertToPy(in.first); - if(!first) - return NULL; - - PyObject *second = TypeConversion::ConvertToPy(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; - } -}; - -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 ConvertFromPy(PyObject *in, QMap &out, int *failIdx) - { - if(!PyDict_Check(in)) - return SWIG_TypeError; - - PyObject *keys = PyDict_Keys(in); - - if(!keys) - return SWIG_TypeError; - - Py_ssize_t len = PyList_Size(keys); - - for(Py_ssize_t i = 0; i < len; i++) - { - K k; - V v; - - PyObject *key = PyList_GetItem(keys, i); - PyObject *value = PyDict_GetItem(in, key); - int ret = TypeConversion::ConvertFromPy(key, k); - int ret2 = TypeConversion::ConvertFromPy(value, v); - if(!SWIG_IsOK(ret) || !SWIG_IsOK(ret2)) - { - if(failIdx) - *failIdx = i; - Py_DecRef(keys); - if(!SWIG_IsOK(ret)) - return ret; - else - return ret2; - } - out.insert(k, v); - } - - Py_DecRef(keys); - - return SWIG_OK; - } - - static int ConvertFromPy(PyObject *in, QMap &out) { return ConvertFromPy(in, out, NULL); } - static PyObject *ConvertToPyInPlace(PyObject *pymap, const QMap &in, int *failIdx) - { - QList keys = in.keys(); - - for(int i = 0; i < keys.size(); i++) - { - const K &k = keys[i]; - PyObject *key = TypeConversion::ConvertToPy(k); - - if(key) - { - PyObject *value = TypeConversion::ConvertToPy(in[k]); - - if(value) - { - PyDict_SetItem(pymap, key, value); - // release our reference - Py_DecRef(key); - // release our reference - Py_DecRef(value); - continue; - } - - // destroy unused key - Py_DecRef(key); - } - - if(failIdx) - *failIdx = i; - - return NULL; - } - - return pymap; - } - - static PyObject *ConvertToPy(const QMap &in, int *failIdx) - { - PyObject *list = PyDict_New(); - if(!list) - return NULL; - - PyObject *ret = ConvertToPyInPlace(list, in, failIdx); - - // if a failure happened, don't leak the map we created - if(!ret) - Py_XDECREF(list); - - return ret; - } - - static PyObject *ConvertToPy(const QMap &in) { return ConvertToPy(in, NULL); } -}; - -#endif diff --git a/qrenderdoc/Code/pyrenderdoc/renderdoc.i b/qrenderdoc/Code/pyrenderdoc/renderdoc.i index ef0f1bc42..815c84d2a 100644 --- a/qrenderdoc/Code/pyrenderdoc/renderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/renderdoc.i @@ -51,13 +51,21 @@ %rename("%(regex:/^VKPipe::(.*)/VK\\1/)s", regextarget=1, fullname=1, %$isclass) "VKPipe::.*"; %begin %{ + #undef slots +%} -#undef slots - +%{ + #include "datetime.h" +%} +%init %{ + PyDateTime_IMPORT; %} %include "pyconversion.i" +// completely ignore rdcdatetime, we custom convert to/from a native python datetime +%ignore rdcdatetime; + // ignore some operators SWIG doesn't have to worry about %ignore SDType::operator=; %ignore StructuredObjectList::swap; @@ -120,6 +128,7 @@ } SIMPLE_TYPEMAPS(rdcstr) +SIMPLE_TYPEMAPS(rdcdatetime) SIMPLE_TYPEMAPS(bytebuf) FIXED_ARRAY_TYPEMAPS(ResourceId) diff --git a/qrenderdoc/Windows/MainWindow.cpp b/qrenderdoc/Windows/MainWindow.cpp index 005c79423..f759fa3b0 100644 --- a/qrenderdoc/Windows/MainWindow.cpp +++ b/qrenderdoc/Windows/MainWindow.cpp @@ -229,7 +229,7 @@ MainWindow::MainWindow(ICaptureContext &ctx) : QMainWindow(NULL), ui(new Ui::Mai for(const BugReport &b : bugs) { // check bugs every two days - qint64 diff = b.checkDate.secsTo(now); + qint64 diff = QDateTime(b.checkDate).secsTo(now); if(diff > 2 * 24 * 60 * 60) { // update the check date on the stored bug @@ -1001,8 +1001,8 @@ void MainWindow::PopulateReportedBugs() if(bug.unreadUpdates) fmt = tr("&%1: (Update) Bug reported at %2"); - QAction *action = - ui->menu_Reported_Bugs->addAction(fmt.arg(idx).arg(bug.submitDate.toString()), [this, i] { + QAction *action = ui->menu_Reported_Bugs->addAction( + fmt.arg(idx).arg(QDateTime(bug.submitDate).toString()), [this, i] { BugReport &bug = m_Ctx.Config().CrashReport_ReportedBugs[i]; QDesktopServices::openUrl(QString(bug.URL())); diff --git a/qrenderdoc/qrenderdoc_local.vcxproj b/qrenderdoc/qrenderdoc_local.vcxproj index bc1547637..6c34bb88d 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj +++ b/qrenderdoc/qrenderdoc_local.vcxproj @@ -894,7 +894,6 @@ - diff --git a/qrenderdoc/qrenderdoc_local.vcxproj.filters b/qrenderdoc/qrenderdoc_local.vcxproj.filters index abc106382..951679304 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj.filters +++ b/qrenderdoc/qrenderdoc_local.vcxproj.filters @@ -1031,9 +1031,6 @@ Code\pyrenderdoc - - Code\pyrenderdoc - Code\pyrenderdoc diff --git a/renderdoc/api/replay/basic_types.h b/renderdoc/api/replay/basic_types.h index eacde46bb..a0e995974 100644 --- a/renderdoc/api/replay/basic_types.h +++ b/renderdoc/api/replay/basic_types.h @@ -50,6 +50,71 @@ typedef uint8_t byte; #define DOCUMENT4(text1, text2, text3, text4) #endif +// primarily here just to remove a dependency on QDateTime in the Qt UI, so we don't have to bind +// against Qt at all in the interface. +DOCUMENT(""); +struct rdcdatetime +{ + DOCUMENT(""); + int32_t year = 0; + int32_t month = 0; + int32_t day = 0; + int32_t hour = 0; + int32_t minute = 0; + int32_t second = 0; + int32_t microsecond = 0; + + rdcdatetime() = default; + + rdcdatetime(int y, int mn, int d, int h = 0, int m = 0, int s = 0, int us = 0) + : year(y), month(mn), day(d), hour(h), minute(m), second(s), microsecond(us) + { + } + + bool operator==(const rdcdatetime &o) const + { + return year == o.year && month == o.month && day == o.day && hour == o.hour && + minute == o.minute && second == o.second && microsecond == o.microsecond; + } + bool operator!=(const rdcdatetime &o) const { return !(*this == o); } + bool operator<(const rdcdatetime &o) const + { + if(year != o.year) + return year < o.year; + if(month != o.month) + return month < o.month; + if(day != o.day) + return day < o.day; + if(hour != o.hour) + return hour < o.hour; + if(minute != o.minute) + return minute < o.minute; + if(second != o.second) + return second < o.second; + if(microsecond != o.microsecond) + return microsecond < o.microsecond; + return false; + } + +#if defined(RENDERDOC_QT_COMPAT) + rdcdatetime(const QDateTime &in) + { + year = in.date().year(); + month = in.date().month(); + day = in.date().day(); + hour = in.time().hour(); + minute = in.time().minute(); + second = in.time().second(); + microsecond = in.time().msec() * 1000; + } + operator QDateTime() const + { + return QDateTime(QDate(year, month, day), QTime(hour, minute, second, microsecond / 1000)); + } + operator QVariant() const { return QVariant(QDateTime(*this)); } +#endif +}; + // here we define our own data structures that are ABI compatible between modules, as STL is not // safe to pass a module boundary. template