diff --git a/src/SHADERed/Objects/PluginAPI/Plugin.h b/src/SHADERed/Objects/PluginAPI/Plugin.h index 4bef7f76..5e2e1756 100644 --- a/src/SHADERed/Objects/PluginAPI/Plugin.h +++ b/src/SHADERed/Objects/PluginAPI/Plugin.h @@ -97,7 +97,7 @@ namespace ed { typedef int (*GetIncludePathCountFn)(); typedef const char* (*GetIncludePathFn)(void* project, int index); typedef const char* (*GetMessagesCurrentItemFn)(void* messages); - + typedef void (*OnEditorContentChangeFn)(void* UI, void* plugin, int langID, int editorID); typedef unsigned int* (*GetPipelineItemSPIRVFn)(void* item, ed::plugin::ShaderStage stage, int* dataLen); typedef void (*RegisterShortcutFn)(void* plugin, const char* name); @@ -132,7 +132,6 @@ namespace ed { typedef float (*ScaleSizeFn)(float size); - /********** IPlugin2 **********/ typedef int (*GetHostIPluginMaxVersionFn)(); typedef void (*ImGuiFileDialogOpenFn)(const char* key, const char* title, const char* filter); @@ -148,13 +147,17 @@ namespace ed { typedef void* (*GetEditorPipelineItemFn)(void* UI, void* plugin, int langID, int editorID); typedef void (*SetViewportSizeFn)(float w, float h); typedef int (*IsObjectBoundFn)(void* Objects, const char* name, void* pipelineItem); + typedef void (*DebuggerStepIntoPluginEditorFn)(void* Debugger, void* Code, void* Plugin, int lang, int editor); + typedef void (*DebuggerGetVariableValueFn)(void* Debugger, const char* name, char* value, int valueLength); + typedef void (*DebuggerStopPluginEditorFn)(void* Debugger, void* Code, void* Plugin, int lang, int editor); + typedef bool (*DebuggerIsVMRunningFn)(void* Debugger); } // CreatePlugin(), DestroyPlugin(ptr), GetPluginAPIVersion(), GetPluginVersion(), GetPluginName() class IPlugin1 { public: virtual int GetVersion() { return 1; } - + virtual bool Init(bool isWeb, int sedVersion) = 0; virtual void InitUI(void* ctx) = 0; virtual void OnEvent(void* e) = 0; // e is &SDL_Event @@ -342,7 +345,7 @@ namespace ed { virtual void HandlePluginMessage(const char* sender, char* msg, int msgLen) = 0; virtual void HandleApplicationEvent(ed::plugin::ApplicationEvent event, void* data1, void* data2) = 0; virtual void HandleNotification(int id) = 0; - + // host functions void *Renderer, *Messages, *Project, *UI, *ObjectManager, *PipelineManager, *Plugins, *Debugger; pluginfn::AddObjectFn AddObject; @@ -460,7 +463,7 @@ namespace ed { virtual bool PipelineItem_SupportsImmediateMode(const char* type, void* data, ed::plugin::ShaderStage stage) = 0; virtual bool PipelineItem_HasCustomImmediateModeCompiler(const char* type, void* data, ed::plugin::ShaderStage stage) = 0; virtual bool PipelineItem_ImmediateModeCompile(const char* type, void* data, ed::plugin::ShaderStage stage, const char* expression) = 0; - + virtual unsigned int ImmediateMode_GetSPIRVSize() = 0; virtual unsigned int* ImmediateMode_GetSPIRV() = 0; virtual unsigned int ImmediateMode_GetVariableCount() = 0; @@ -483,10 +486,15 @@ namespace ed { virtual void PluginManager_RegisterPlugins() = 0; virtual const unsigned int* CustomLanguage_CompileToSPIRV2(void* item, int langID, const char* src, size_t src_len, ed::plugin::ShaderStage stage, const char* entry, ed::plugin::ShaderMacro* macros, size_t macroCount, size_t* spv_length, bool* compiled) = 0; - + virtual void ShaderEditor_SetLineIndicator(int langID, int editorID, int line) = 0; + pluginfn::RegisterPluginFn RegisterPlugin; pluginfn::GetEditorPipelineItemFn GetEditorPipelineItem; pluginfn::SetViewportSizeFn SetViewportSize; pluginfn::IsObjectBoundFn IsObjectBound; + pluginfn::DebuggerStepIntoPluginEditorFn DebuggerStepIntoPluginEditor; + pluginfn::DebuggerGetVariableValueFn DebuggerGetVariableValue; + pluginfn::DebuggerStopPluginEditorFn DebuggerStopPluginEditor; + pluginfn::DebuggerIsVMRunningFn DebuggerIsVMRunning; }; } \ No newline at end of file diff --git a/src/SHADERed/Objects/PluginManager.cpp b/src/SHADERed/Objects/PluginManager.cpp index 5c201bc5..d1d12277 100644 --- a/src/SHADERed/Objects/PluginManager.cpp +++ b/src/SHADERed/Objects/PluginManager.cpp @@ -1048,6 +1048,34 @@ namespace ed { ObjectManager* obj = (ObjectManager*)Objects; return obj->IsBound(obj->Get(name), (PipelineItem*)pipelineItem); }; + plugin3->DebuggerStepIntoPluginEditor = [](void* Debugger, void* UI, void* Plugin, int lang, int editorID) { + ((ed::DebugInformation*)Debugger)->StepInto(); + int curLine = ((ed::DebugInformation*)Debugger)->GetCurrentLine(); + ((IPlugin3*)Plugin)->ShaderEditor_SetLineIndicator(lang, editorID, curLine); + }; + plugin3->DebuggerGetVariableValue = [](void* Debugger, const char* name, char* value, int valueLength) { + ed::DebugInformation* dbgr = ((ed::DebugInformation*)Debugger); + + spvm_result_t memType; + size_t memCount = 0; + spvm_member_t mem = dbgr->GetVariable(name, memCount, memType); + + std::stringstream ss; + dbgr->GetVariableValueAsString(ss, dbgr->GetVM(), memType, mem, memCount, ""); + + std::string res = ss.str(); + if (res.size() >= valueLength - 1) + res = res.substr(0, valueLength - 1); + + strcpy(value, res.c_str()); + }; + plugin3->DebuggerStopPluginEditor = [](void* Debugger, void* UI, void* Plugin, int lang, int editorID) { + ((ed::DebugInformation*)Debugger)->SetDebugging(false); + ((IPlugin3*)Plugin)->ShaderEditor_SetLineIndicator(lang, editorID, -1); + }; + plugin3->DebuggerIsVMRunning = [](void* Debugger) -> bool { + return ((ed::DebugInformation*)Debugger)->IsVMRunning(); + }; } #ifdef SHADERED_DESKTOP @@ -1059,8 +1087,24 @@ namespace ed { if (initResult) ed::Logger::Get().Log("Plugin \"" + pname + "\" successfully initialized."); - else + else { ed::Logger::Get().Log("Failed to initialize plugin \"" + pname + "\"."); + +#if defined(__linux__) || defined(__unix__) || defined(__APPLE__) + DestroyPluginFn fnDestroyPlugin = (DestroyPluginFn)dlsym(procDLL, "DestroyPlugin"); + if (fnDestroyPlugin) + (*fnDestroyPlugin)(plugin); + + dlclose(procDLL); +#else + DestroyPluginFn fnDestroyPlugin = (DestroyPluginFn)GetProcAddress((HINSTANCE)procDLL, "DestroyPlugin"); + if (fnDestroyPlugin) + (*fnDestroyPlugin)(plugin); + + FreeLibrary((HINSTANCE)procDLL); +#endif + return; + } m_plugins.push_back(plugin); m_proc.push_back(procDLL); diff --git a/src/SHADERed/Objects/WebAPI.cpp b/src/SHADERed/Objects/WebAPI.cpp index f65562a5..478cdc7e 100644 --- a/src/SHADERed/Objects/WebAPI.cpp +++ b/src/SHADERed/Objects/WebAPI.cpp @@ -21,7 +21,7 @@ namespace ed { const std::string WebAPI::URL = "http://api.shadered.org"; - const char* WebAPI::Version = "1.5.4"; + const char* WebAPI::Version = "1.5.5"; bool isDigitsOnly(const std::string& str) { diff --git a/src/SHADERed/Objects/WebAPI.h b/src/SHADERed/Objects/WebAPI.h index d17a23e8..aaf672d7 100644 --- a/src/SHADERed/Objects/WebAPI.h +++ b/src/SHADERed/Objects/WebAPI.h @@ -7,7 +7,7 @@ namespace ed { class WebAPI { public: static const std::string URL; - static const int InternalVersion = 25; + static const int InternalVersion = 26; static const char* Version; // info that /api/search will return diff --git a/src/SHADERed/Options.h b/src/SHADERed/Options.h index f2cc6ed7..36a1a714 100644 --- a/src/SHADERed/Options.h +++ b/src/SHADERed/Options.h @@ -11,7 +11,7 @@ #define SHADERED_DESKTOP // #define SHADERED_WEB -#define SHADERED_VERSION 1005004 +#define SHADERED_VERSION 1005005 #define DEBUG_ID_START 1 #define DEBUG_PRIMITIVE_GROUP 170 diff --git a/src/SHADERed/UI/CodeEditorUI.cpp b/src/SHADERed/UI/CodeEditorUI.cpp index 5fb283cc..59c6ac83 100644 --- a/src/SHADERed/UI/CodeEditorUI.cpp +++ b/src/SHADERed/UI/CodeEditorUI.cpp @@ -1327,6 +1327,29 @@ namespace ed { return nullptr; } + PluginShaderEditor CodeEditorUI::GetPluginEditor(PipelineItem* item, ed::ShaderStage stage) + { + for (int i = 0; i < m_items.size(); i++) + if (m_items[i] == item && m_shaderStage[i] == stage) + return m_pluginEditor[i]; + return PluginShaderEditor(); + } + PluginShaderEditor CodeEditorUI::GetPluginEditor(const std::string& path) + { + for (int i = 0; i < m_paths.size(); i++) + if (m_paths[i] == path) + return m_pluginEditor[i]; + return PluginShaderEditor(); + } + std::string CodeEditorUI::GetPluginEditorPath(const PluginShaderEditor& editor) + { + for (int i = 0; i < m_pluginEditor.size(); i++) + if (m_pluginEditor[i].ID == editor.ID && m_pluginEditor[i].LanguageID == editor.LanguageID && + m_pluginEditor[i].Plugin == editor.Plugin) + return m_paths[i]; + return ""; + } + void CodeEditorUI::CloseAll(PipelineItem* item) { for (int i = 0; i < m_items.size(); i++) { @@ -1456,9 +1479,14 @@ namespace ed { void CodeEditorUI::StopDebugging() { - for (auto& ed : m_editor) { - if (ed) - ed->SetCurrentLineIndicator(-1); + for (int i = 0; i < m_editor.size(); i++) { + if (m_editor[i]) + m_editor[i]->SetCurrentLineIndicator(-1); + else { + if (m_pluginEditor[i].Plugin->GetVersion() >= 3) + ((IPlugin3*)m_pluginEditor[i].Plugin)->ShaderEditor_SetLineIndicator(m_pluginEditor[i].LanguageID, + m_pluginEditor[i].ID, -1); + } } } void CodeEditorUI::StopThreads() diff --git a/src/SHADERed/UI/CodeEditorUI.h b/src/SHADERed/UI/CodeEditorUI.h index 90a844fe..86907561 100644 --- a/src/SHADERed/UI/CodeEditorUI.h +++ b/src/SHADERed/UI/CodeEditorUI.h @@ -22,6 +22,24 @@ namespace ed { std::string Code; }; + struct PluginShaderEditor { + PluginShaderEditor() + { + Plugin = nullptr; + LanguageID = -1; + ID = -1; + } + PluginShaderEditor(IPlugin1* pl, int langID, int id) + { + Plugin = pl; + LanguageID = langID; + ID = id; + } + IPlugin1* Plugin; + int LanguageID; + int ID; + }; + class CodeEditorUI : public UIView { public: CodeEditorUI(GUIManager* ui, ed::InterfaceManager* objects, const std::string& name = "", bool visible = false); @@ -50,6 +68,9 @@ namespace ed { void OpenPluginCode(PipelineItem* item, const char* filepath, int id); TextEditor* Get(PipelineItem* item, ed::ShaderStage stage); TextEditor* Get(const std::string& path); + PluginShaderEditor GetPluginEditor(PipelineItem* item, ed::ShaderStage stage); + PluginShaderEditor GetPluginEditor(const std::string& path); + std::string GetPluginEditorPath(const PluginShaderEditor& editor); void SetTheme(const TextEditor::Palette& colors); @@ -98,24 +119,6 @@ namespace ed { std::vector m_snippets; - struct PluginShaderEditor { - PluginShaderEditor() - { - Plugin = nullptr; - LanguageID = -1; - ID = -1; - } - PluginShaderEditor(IPlugin1* pl, int langID, int id) - { - Plugin = pl; - LanguageID = langID; - ID = id; - } - IPlugin1* Plugin; - int LanguageID; - int ID; - }; - // code editor font ImFont* m_font; diff --git a/src/SHADERed/UI/PipelineUI.cpp b/src/SHADERed/UI/PipelineUI.cpp index 41f4236e..9e98c003 100644 --- a/src/SHADERed/UI/PipelineUI.cpp +++ b/src/SHADERed/UI/PipelineUI.cpp @@ -189,9 +189,12 @@ namespace ed { codeUI->StopDebugging(); codeUI->Open(m_modalItem, ShaderStage::Compute); TextEditor* editor = codeUI->Get(m_modalItem, ShaderStage::Compute); + PluginShaderEditor pluginEditor; + if (editor == nullptr) + pluginEditor = codeUI->GetPluginEditor(m_modalItem, ShaderStage::Compute); m_data->Debugger.PrepareComputeShader(m_modalItem, m_thread[0], m_thread[1], m_thread[2]); - ((PixelInspectUI*)m_ui->Get(ViewID::PixelInspect))->StartDebugging(editor, nullptr); + ((PixelInspectUI*)m_ui->Get(ViewID::PixelInspect))->StartDebugging(editor, pluginEditor, nullptr); m_closePopup(); } diff --git a/src/SHADERed/UI/PixelInspectUI.cpp b/src/SHADERed/UI/PixelInspectUI.cpp index 7efe88a9..5f955e11 100644 --- a/src/SHADERed/UI/PixelInspectUI.cpp +++ b/src/SHADERed/UI/PixelInspectUI.cpp @@ -95,9 +95,12 @@ namespace ed { codeUI->StopDebugging(); codeUI->Open(suggestion.Item, ShaderStage::Compute); TextEditor* editor = codeUI->Get(suggestion.Item, ShaderStage::Compute); + PluginShaderEditor pluginEditor; + if (editor == nullptr) + pluginEditor = codeUI->GetPluginEditor(suggestion.Item, ShaderStage::Compute); m_data->Debugger.PrepareComputeShader(suggestion.Item, suggestion.Thread.x, suggestion.Thread.y, suggestion.Thread.z); - this->StartDebugging(editor, nullptr); + this->StartDebugging(editor, pluginEditor, nullptr); } ImGui::SameLine(); @@ -158,6 +161,7 @@ namespace ed { } else { ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + PluginShaderEditor pluginEditor; TextEditor* editor = nullptr; bool requestCompile = false; int initIndex = 0; @@ -191,6 +195,8 @@ namespace ed { // for plugins that store vertex and pixel shader in the same file if (editor == nullptr && pixel.Pass->Type == PipelineItem::ItemType::PluginItem) editor = codeUI->Get(pixel.Pass, ShaderStage::Vertex); + if (editor == nullptr) + pluginEditor = codeUI->GetPluginEditor(pixel.Pass, ShaderStage::Pixel); m_data->Debugger.PreparePixelShader(pixel.Pass, pixel.Object); m_data->Debugger.SetPixelShaderInput(pixel); @@ -230,6 +236,9 @@ namespace ed { } editor = codeUI->Get(pixel.Pass, ShaderStage::Vertex); + if (editor == nullptr) + pluginEditor = codeUI->GetPluginEditor(pixel.Pass, ShaderStage::Vertex); + m_data->Debugger.PrepareVertexShader(pixel.Pass, pixel.Object); m_data->Debugger.SetVertexShaderInput(pixel, i); @@ -253,6 +262,9 @@ namespace ed { codeUI->Open(pixel.Pass, ShaderStage::Geometry); editor = codeUI->Get(pixel.Pass, ShaderStage::Geometry); + if (editor == nullptr) + pluginEditor = codeUI->GetPluginEditor(pixel.Pass, ShaderStage::Geometry); + m_data->Debugger.PrepareGeometryShader(pixel.Pass, pixel.Object); m_data->Debugger.SetGeometryShaderInput(pixel); @@ -270,6 +282,9 @@ namespace ed { codeUI->Open(pixel.Pass, ShaderStage::TessellationControl); editor = codeUI->Get(pixel.Pass, ShaderStage::TessellationControl); + if (editor == nullptr) + pluginEditor = codeUI->GetPluginEditor(pixel.Pass, ShaderStage::TessellationControl); + m_data->Debugger.PrepareTessellationControlShader(pixel.Pass, pixel.Object); m_data->Debugger.SetTessellationControlShaderInput(pixel); @@ -280,8 +295,8 @@ namespace ed { } /* ACTUAL ACTION HERE */ - if (requestCompile && editor != nullptr) - StartDebugging(editor, &pixel); + if (requestCompile) + StartDebugging(editor, pluginEditor, &pixel); ImGui::PopStyleColor(); } @@ -291,26 +306,38 @@ namespace ed { ImGui::EndChild(); ImGui::NewLine(); } - void PixelInspectUI::StartDebugging(TextEditor* editor, PixelInformation* pixel) + void PixelInspectUI::StartDebugging(TextEditor* editor, const PluginShaderEditor& pluginEditor, PixelInformation* pixel) { Logger::Get().Log("Starting up the debugger"); + + CodeEditorUI* codeEditor = (reinterpret_cast(m_ui->Get(ViewID::Code))); - m_data->Debugger.SetCurrentFile(editor->GetPath()); + std::string path = ""; + if (editor != nullptr) + path = editor->GetPath(); + else + path = codeEditor->GetPluginEditorPath(pluginEditor); + + + m_data->Debugger.SetCurrentFile(path); m_data->Debugger.SetDebugging(true); m_data->Debugger.PrepareDebugger(); // text editor stack m_editorStack.clear(); - m_editorStack.push_back(editor->GetPath()); + m_editorStack.push_back(path); // start the DAP server - m_data->DAP.StartDebugging(editor->GetPath(), m_data->Debugger.GetStage()); + m_data->DAP.StartDebugging(path, m_data->Debugger.GetStage()); // skip initialization - editor->SetCurrentLineIndicator(m_data->Debugger.GetCurrentLine()); + if (editor != nullptr) + editor->SetCurrentLineIndicator(m_data->Debugger.GetCurrentLine()); + else if (pluginEditor.Plugin->GetVersion() >= 3) + ((IPlugin3*)pluginEditor.Plugin)->ShaderEditor_SetLineIndicator(pluginEditor.LanguageID, pluginEditor.ID, m_data->Debugger.GetCurrentLine()); if (pixel) - m_data->Plugins.HandleApplicationEvent(ed::plugin::ApplicationEvent::DebuggerStarted, pixel->Pass->Name, (void*)editor); + m_data->Plugins.HandleApplicationEvent(ed::plugin::ApplicationEvent::DebuggerStarted, pixel->Pass->Name, editor != nullptr ? (void*)editor : (void*)&pluginEditor); // reset function stack ((DebugFunctionStackUI*)m_ui->Get(ViewID::DebugFunctionStack))->Refresh(); @@ -329,276 +356,280 @@ namespace ed { m_data->Debugger.UpdateVectorWatchValue(i); // editor functions - editor->OnDebuggerAction = [&](TextEditor* ed, TextEditor::DebugAction act) { - if (!m_data->Debugger.IsDebugging()) - return; - - m_cacheExpression.clear(); - - bool state = m_data->Debugger.IsVMRunning(); - switch (act) { - case TextEditor::DebugAction::Continue: - m_data->Debugger.Continue(); - break; - case TextEditor::DebugAction::Step: - m_data->Debugger.Step(); - break; - case TextEditor::DebugAction::StepInto: - m_data->Debugger.StepInto(); - break; - case TextEditor::DebugAction::StepOut: - m_data->Debugger.StepOut(); - break; - } + if (editor) { + editor->OnDebuggerAction = [&](TextEditor* ed, TextEditor::DebugAction act) { + if (!m_data->Debugger.IsDebugging()) + return; + + m_cacheExpression.clear(); + + bool state = m_data->Debugger.IsVMRunning(); + switch (act) { + case TextEditor::DebugAction::Continue: + m_data->Debugger.Continue(); + break; + case TextEditor::DebugAction::Step: + m_data->Debugger.Step(); + break; + case TextEditor::DebugAction::StepInto: + m_data->Debugger.StepInto(); + break; + case TextEditor::DebugAction::StepOut: + m_data->Debugger.StepOut(); + break; + } - if (m_data->Debugger.GetVM()->discarded) - state = false; + if (m_data->Debugger.GetVM()->discarded) + state = false; - if (act == TextEditor::DebugAction::Stop || !state) { - m_data->Debugger.SetDebugging(false); + if (act == TextEditor::DebugAction::Stop || !state) { + m_data->Debugger.SetDebugging(false); - ed->SetCurrentLineIndicator(-1); + ed->SetCurrentLineIndicator(-1); - // stop debugging in all editors - CodeEditorUI* codeEditor = ((CodeEditorUI*)m_ui->Get(ed::ViewID::Code)); - for (int i = 0; i < m_editorStack.size(); i++) - if (codeEditor->Get(m_editorStack[i])) - codeEditor->Get(m_editorStack[i])->SetCurrentLineIndicator(-1); + // stop debugging in all editors + for (int i = 0; i < m_editorStack.size(); i++) { + if (codeEditor->Get(m_editorStack[i])) + codeEditor->Get(m_editorStack[i])->SetCurrentLineIndicator(-1); + else { + PluginShaderEditor pluginEditor = codeEditor->GetPluginEditor(m_editorStack[i]); - m_data->Plugins.HandleApplicationEvent(ed::plugin::ApplicationEvent::DebuggerStopped, nullptr, nullptr); - } else { - // update all the debug windows + if (pluginEditor.Plugin->GetVersion() >= 3) + ((IPlugin3*)pluginEditor.Plugin)->ShaderEditor_SetLineIndicator(pluginEditor.LanguageID, pluginEditor.ID, -1); + } + } + + m_data->Plugins.HandleApplicationEvent(ed::plugin::ApplicationEvent::DebuggerStopped, nullptr, nullptr); + } else { + // update all the debug windows + ((DebugWatchUI*)m_ui->Get(ViewID::DebugWatch))->Refresh(); + ((DebugVectorWatchUI*)m_ui->Get(ViewID::DebugVectorWatch))->Refresh(); + ((DebugFunctionStackUI*)m_ui->Get(ViewID::DebugFunctionStack))->Refresh(); + ((DebugValuesUI*)m_ui->Get(ViewID::DebugValues))->Refresh(); + if (m_data->Debugger.GetStage() == ShaderStage::TessellationControl) + ((DebugTessControlOutputUI*)m_ui->Get(ViewID::DebugTessControlOutput))->Refresh(); + + int curLine = m_data->Debugger.GetCurrentLine(); + bool vmRunning = m_data->Debugger.IsVMRunning(); + + // get filename + std::string curFile = m_data->Debugger.GetVM()->current_file ? m_data->Debugger.GetVM()->current_file : ""; + if (curFile.empty() || curFile == "src/lib.rs" || curFile == "src\\lib.rs") // hack for PluginRust.. + curFile = m_data->Debugger.GetCurrentFile(); + else if (!std::filesystem::path(curFile).is_absolute()) + curFile = m_data->Parser.GetProjectPath(curFile); + + // open the file if it's not already open + if (codeEditor->Get(curFile) == nullptr) + codeEditor->OpenFile(curFile); + + TextEditor* actualEditor = codeEditor->Get(curFile); + + // stop debugging in all editors + bool deleteStack = false; + for (int i = 0; i < m_editorStack.size(); i++) { + if (deleteStack || (i > 0 && !vmRunning)) { + if (codeEditor->Get(m_editorStack[i])) + codeEditor->Get(m_editorStack[i])->SetCurrentLineIndicator(-1); + m_editorStack.erase(m_editorStack.begin() + i); + i--; + } else if (m_editorStack[i] == curFile) + deleteStack = true; + } + if (!deleteStack) + m_editorStack.push_back(curFile); + + // generate "Auto" watches + DebugAutoUI* autoWnd = ((DebugAutoUI*)m_ui->Get(ViewID::DebugAuto)); + if (autoWnd->Visible) + autoWnd->SetExpressions(actualEditor->GetRelevantExpressions(curLine)); + + // update the line indicator + if (!vmRunning) { + curLine = ed->GetCurrentLineIndicator() + 1; + ed->SetCurrentLineIndicator(curLine); + } else + actualEditor->SetCurrentLineIndicator(curLine, actualEditor == ed); + + // copy the debug methods if we are in some other file + if (actualEditor != ed) { + actualEditor->HasIdentifierHover = ed->HasIdentifierHover; + actualEditor->OnIdentifierHover = ed->OnIdentifierHover; + actualEditor->HasExpressionHover = ed->HasExpressionHover; + actualEditor->OnExpressionHover = ed->OnExpressionHover; + } + + m_data->Plugins.HandleApplicationEvent(ed::plugin::ApplicationEvent::DebuggerStepped, (void*)curLine, nullptr); + } + }; + editor->OnDebuggerJump = [&](TextEditor* ed, int line) { + if (!m_data->Debugger.IsDebugging()) + return; + + m_cacheExpression.clear(); + + while (m_data->Debugger.IsVMRunning() && m_data->Debugger.GetCurrentLine() != line) + spvm_state_step_into(m_data->Debugger.GetVM()); + + ed->SetCurrentLineIndicator(m_data->Debugger.GetCurrentLine()); ((DebugWatchUI*)m_ui->Get(ViewID::DebugWatch))->Refresh(); ((DebugVectorWatchUI*)m_ui->Get(ViewID::DebugVectorWatch))->Refresh(); ((DebugFunctionStackUI*)m_ui->Get(ViewID::DebugFunctionStack))->Refresh(); ((DebugValuesUI*)m_ui->Get(ViewID::DebugValues))->Refresh(); if (m_data->Debugger.GetStage() == ShaderStage::TessellationControl) ((DebugTessControlOutputUI*)m_ui->Get(ViewID::DebugTessControlOutput))->Refresh(); + }; + editor->HasIdentifierHover = [&](TextEditor* ed, const std::string& id) -> bool { + if (!m_data->Debugger.IsDebugging() || !Settings::Instance().Debug.ShowValuesOnHover) + return false; + + size_t vcount = 0; + spvm_member_t res = m_data->Debugger.GetVariable(id, vcount); + + return res != nullptr; + }; + editor->OnIdentifierHover = [&](TextEditor* ed, const std::string& id) { + size_t vcount = 0; + spvm_result_t resType = nullptr; + spvm_member_t res = m_data->Debugger.GetVariable(id, vcount, resType); + + if (res != nullptr && resType != nullptr) { + + bool isTex = false, + isCube = false, + isTex3D = false; + + // Type: + if (resType->value_type == spvm_value_type_int && resType->value_sign == 0) + ImGui::Text("uint"); + else if (resType->value_type == spvm_value_type_int) + ImGui::Text("int"); + else if (resType->value_type == spvm_value_type_bool) + ImGui::Text("bool"); + else if (resType->value_type == spvm_value_type_float && resType->value_bitcount > 32) + ImGui::Text("double"); + else if (resType->value_type == spvm_value_type_float) + ImGui::Text("float"); + else if (resType->value_type == spvm_value_type_matrix) + ImGui::Text("matrix"); + else if (resType->value_type == spvm_value_type_vector) + ImGui::Text("vector"); + else if (resType->value_type == spvm_value_type_array) + ImGui::Text("array"); + else if (resType->value_type == spvm_value_type_runtime_array) + ImGui::Text("runtime array"); + else if (resType->value_type == spvm_value_type_struct && resType->name) + ImGui::Text(resType->name); + else if (resType->value_type == spvm_value_type_sampled_image || resType->value_type == spvm_value_type_image) { + isTex = true; + ImGui::Text("texture"); + + if (resType) { + spvm_image_info* image_info = resType->image_info; + + if (image_info == nullptr && m_data->Debugger.GetVM()) { + spvm_result_t type_info = spvm_state_get_type_info(m_data->Debugger.GetVM()->results, resType); + image_info = type_info->image_info; - int curLine = m_data->Debugger.GetCurrentLine(); - bool vmRunning = m_data->Debugger.IsVMRunning(); - - // get filename - std::string curFile = m_data->Debugger.GetVM()->current_file ? m_data->Debugger.GetVM()->current_file : ""; - if (curFile.empty() || curFile == "src/lib.rs" || curFile == "src\\lib.rs") // hack for PluginRust.. - curFile = m_data->Debugger.GetCurrentFile(); - else if (!std::filesystem::path(curFile).is_absolute()) - curFile = m_data->Parser.GetProjectPath(curFile); - - // open the file if it's not already open - CodeEditorUI* codeEditor = ((CodeEditorUI*)m_ui->Get(ed::ViewID::Code)); - if (codeEditor->Get(curFile) == nullptr) - codeEditor->OpenFile(curFile); - - TextEditor* actualEditor = codeEditor->Get(curFile); + if (image_info == NULL) { + type_info = &m_data->Debugger.GetVM()->results[type_info->pointer]; + image_info = type_info->image_info; + } + } - // stop debugging in all editors - bool deleteStack = false; - for (int i = 0; i < m_editorStack.size(); i++) { - if (deleteStack || (i > 0 && !vmRunning)) { - if (codeEditor->Get(m_editorStack[i])) - codeEditor->Get(m_editorStack[i])->SetCurrentLineIndicator(-1); - m_editorStack.erase(m_editorStack.begin() + i); - i--; + if (image_info && image_info->dim == SpvDimCube) + isCube = true; + else if (image_info && image_info->dim == SpvDim3D) + isTex3D = true; + } } - else if (m_editorStack[i] == curFile) - deleteStack = true; - } - if (!deleteStack) - m_editorStack.push_back(curFile); - - // generate "Auto" watches - DebugAutoUI* autoWnd = ((DebugAutoUI*)m_ui->Get(ViewID::DebugAuto)); - if (autoWnd->Visible) - autoWnd->SetExpressions(actualEditor->GetRelevantExpressions(curLine)); - - // update the line indicator - if (!vmRunning) { - curLine = ed->GetCurrentLineIndicator() + 1; - ed->SetCurrentLineIndicator(curLine); - } else - actualEditor->SetCurrentLineIndicator(curLine, actualEditor == ed); - - // copy the debug methods if we are in some other file - if (actualEditor != ed) { - actualEditor->HasIdentifierHover = ed->HasIdentifierHover; - actualEditor->OnIdentifierHover = ed->OnIdentifierHover; - actualEditor->HasExpressionHover = ed->HasExpressionHover; - actualEditor->OnExpressionHover = ed->OnExpressionHover; - } - m_data->Plugins.HandleApplicationEvent(ed::plugin::ApplicationEvent::DebuggerStepped, (void*)curLine, nullptr); - } - }; - editor->OnDebuggerJump = [&](TextEditor* ed, int line) { - if (!m_data->Debugger.IsDebugging()) - return; - - m_cacheExpression.clear(); - - while (m_data->Debugger.IsVMRunning() && m_data->Debugger.GetCurrentLine() != line) - spvm_state_step_into(m_data->Debugger.GetVM()); - - ed->SetCurrentLineIndicator(m_data->Debugger.GetCurrentLine()); - ((DebugWatchUI*)m_ui->Get(ViewID::DebugWatch))->Refresh(); - ((DebugVectorWatchUI*)m_ui->Get(ViewID::DebugVectorWatch))->Refresh(); - ((DebugFunctionStackUI*)m_ui->Get(ViewID::DebugFunctionStack))->Refresh(); - ((DebugValuesUI*)m_ui->Get(ViewID::DebugValues))->Refresh(); - if (m_data->Debugger.GetStage() == ShaderStage::TessellationControl) - ((DebugTessControlOutputUI*)m_ui->Get(ViewID::DebugTessControlOutput))->Refresh(); - }; - editor->HasIdentifierHover = [&](TextEditor* ed, const std::string& id) -> bool { - if (!m_data->Debugger.IsDebugging() || !Settings::Instance().Debug.ShowValuesOnHover) - return false; - - size_t vcount = 0; - spvm_member_t res = m_data->Debugger.GetVariable(id, vcount); - - return res != nullptr; - }; - editor->OnIdentifierHover = [&](TextEditor* ed, const std::string& id) { - size_t vcount = 0; - spvm_result_t resType = nullptr; - spvm_member_t res = m_data->Debugger.GetVariable(id, vcount, resType); - - if (res != nullptr && resType != nullptr) { - - bool isTex = false, - isCube = false, - isTex3D = false; - - // Type: - if (resType->value_type == spvm_value_type_int && resType->value_sign == 0) - ImGui::Text("uint"); - else if (resType->value_type == spvm_value_type_int) - ImGui::Text("int"); - else if (resType->value_type == spvm_value_type_bool) - ImGui::Text("bool"); - else if (resType->value_type == spvm_value_type_float && resType->value_bitcount > 32) - ImGui::Text("double"); - else if (resType->value_type == spvm_value_type_float) - ImGui::Text("float"); - else if (resType->value_type == spvm_value_type_matrix) - ImGui::Text("matrix"); - else if (resType->value_type == spvm_value_type_vector) - ImGui::Text("vector"); - else if (resType->value_type == spvm_value_type_array) - ImGui::Text("array"); - else if (resType->value_type == spvm_value_type_runtime_array) - ImGui::Text("runtime array"); - else if (resType->value_type == spvm_value_type_struct && resType->name) - ImGui::Text(resType->name); - else if (resType->value_type == spvm_value_type_sampled_image || resType->value_type == spvm_value_type_image) { - isTex = true; - ImGui::Text("texture"); - - if (resType) { - spvm_image_info* image_info = resType->image_info; - - if (image_info == nullptr && m_data->Debugger.GetVM()) { - spvm_result_t type_info = spvm_state_get_type_info(m_data->Debugger.GetVM()->results, resType); - image_info = type_info->image_info; - - if (image_info == NULL) { - type_info = &m_data->Debugger.GetVM()->results[type_info->pointer]; - image_info = type_info->image_info; + ImGui::Separator(); + + // Value: + if (isTex && res->image_data != nullptr) { + spvm_image_t tex = res->image_data; + + if (isCube) { + m_cubePrev.Draw((GLuint)((uintptr_t)tex->user_data)); + ImGui::Image((ImTextureID)m_cubePrev.GetTexture(), ImVec2(128.0f, 128.0f * (375.0f / 512.0f)), ImVec2(0, 1), ImVec2(1, 0)); + } else if (isTex3D) { + float imgWH = (tex->height / (float)tex->width); + m_tex3DPrev.Draw((GLuint)((uintptr_t)tex->user_data), 128.0f, 128.0f * (float)imgWH); + ImGui::Image((void*)(intptr_t)m_tex3DPrev.GetTexture(), ImVec2(128.0f, 128.0f * imgWH)); + } else + ImGui::Image((ImTextureID)tex->user_data, ImVec2(128.0f, 128.0f * (tex->height / (float)tex->width)), ImVec2(0, 1), ImVec2(1, 0)); + } else { + // color preview + if (resType->value_type == spvm_value_type_vector && m_data->Debugger.GetVM()->results[resType->pointer].value_type == spvm_value_type_float) { + if (resType->member_count == 3) { + float colorVal[3] = { res[0].value.f, res[1].value.f, res[2].value.f }; + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::ColorEdit3("##value_preview", colorVal, ImGuiColorEditFlags_NoInputs); + ImGui::PopItemFlag(); + ImGui::SameLine(); + } else if (resType->member_count == 4) { + float colorVal[4] = { res[0].value.f, res[1].value.f, res[2].value.f, res[3].value.f }; + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::ColorEdit4("##value_preview", colorVal, ImGuiColorEditFlags_NoInputs); + ImGui::PopItemFlag(); + ImGui::SameLine(); } } - if (image_info && image_info->dim == SpvDimCube) - isCube = true; - else if (image_info && image_info->dim == SpvDim3D) - isTex3D = true; + // text value + std::stringstream ss; + m_data->Debugger.GetVariableValueAsString(ss, m_data->Debugger.GetVM(), resType, res, vcount, ""); + ImGui::Text(ss.str().c_str()); } } + }; + editor->HasExpressionHover = [&](TextEditor* ed, const std::string& id) -> bool { + if (!m_data->Debugger.IsDebugging() || !Settings::Instance().Debug.ShowValuesOnHover) + return false; - ImGui::Separator(); + if (id == m_cacheExpression) + return m_cacheExists; - // Value: - if (isTex && res->image_data != nullptr) { - spvm_image_t tex = res->image_data; + m_cacheExpression = id; - if (isCube) { - m_cubePrev.Draw((GLuint)((uintptr_t)tex->user_data)); - ImGui::Image((ImTextureID)m_cubePrev.GetTexture(), ImVec2(128.0f, 128.0f * (375.0f / 512.0f)), ImVec2(0, 1), ImVec2(1, 0)); - } - else if (isTex3D) { - float imgWH = (tex->height / (float)tex->width); - m_tex3DPrev.Draw((GLuint)((uintptr_t)tex->user_data), 128.0f, 128.0f * (float)imgWH); - ImGui::Image((void*)(intptr_t)m_tex3DPrev.GetTexture(), ImVec2(128.0f, 128.0f * imgWH)); - } - else - ImGui::Image((ImTextureID)tex->user_data, ImVec2(128.0f, 128.0f * (tex->height / (float)tex->width)), ImVec2(0, 1), ImVec2(1, 0)); - } else { - // color preview - if (resType->value_type == spvm_value_type_vector && m_data->Debugger.GetVM()->results[resType->pointer].value_type == spvm_value_type_float) { - if (resType->member_count == 3) { - float colorVal[3] = { res[0].value.f, res[1].value.f, res[2].value.f }; - ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); - ImGui::ColorEdit3("##value_preview", colorVal, ImGuiColorEditFlags_NoInputs); - ImGui::PopItemFlag(); - ImGui::SameLine(); - } else if (resType->member_count == 4) { - float colorVal[4] = { res[0].value.f, res[1].value.f, res[2].value.f, res[3].value.f }; - ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); - ImGui::ColorEdit4("##value_preview", colorVal, ImGuiColorEditFlags_NoInputs); - ImGui::PopItemFlag(); - ImGui::SameLine(); - } - } + spvm_result_t resType = nullptr; + spvm_result_t exprVal = m_data->Debugger.Immediate(id, resType); + + m_cacheExists = exprVal != nullptr && resType != nullptr; - // text value + if (m_cacheExists) { std::stringstream ss; - m_data->Debugger.GetVariableValueAsString(ss, m_data->Debugger.GetVM(), resType, res, vcount, ""); - ImGui::Text(ss.str().c_str()); + m_data->Debugger.GetVariableValueAsString(ss, m_data->Debugger.GetVMImmediate(), resType, exprVal->members, exprVal->member_count, ""); + + m_cacheValue = ss.str(); + m_cacheHasColor = false; + m_cacheColor = glm::vec4(0.0f); + + if (resType->value_type == spvm_value_type_vector && m_data->Debugger.GetVMImmediate()->results[resType->pointer].value_type == spvm_value_type_float) { + if (resType->member_count == 3) + m_cacheHasColor = true; + else if (resType->member_count == 4) + m_cacheHasColor = true; + for (int i = 0; i < resType->member_count; i++) + m_cacheColor[i] = exprVal->members[i].value.f; + } } - } - }; - editor->HasExpressionHover = [&](TextEditor* ed, const std::string& id) -> bool { - if (!m_data->Debugger.IsDebugging() || !Settings::Instance().Debug.ShowValuesOnHover) - return false; - if (id == m_cacheExpression) return m_cacheExists; - - m_cacheExpression = id; - - spvm_result_t resType = nullptr; - spvm_result_t exprVal = m_data->Debugger.Immediate(id, resType); - - m_cacheExists = exprVal != nullptr && resType != nullptr; - - if (m_cacheExists) { - std::stringstream ss; - m_data->Debugger.GetVariableValueAsString(ss, m_data->Debugger.GetVMImmediate(), resType, exprVal->members, exprVal->member_count, ""); - - m_cacheValue = ss.str(); - m_cacheHasColor = false; - m_cacheColor = glm::vec4(0.0f); - - if (resType->value_type == spvm_value_type_vector && m_data->Debugger.GetVMImmediate()->results[resType->pointer].value_type == spvm_value_type_float) { - if (resType->member_count == 3) - m_cacheHasColor = true; - else if (resType->member_count == 4) - m_cacheHasColor = true; - for (int i = 0; i < resType->member_count; i++) - m_cacheColor[i] = exprVal->members[i].value.f; + }; + editor->OnExpressionHover = [&](TextEditor* ed, const std::string& id) { + ImGui::Text(id.c_str()); + ImGui::Separator(); + if (m_cacheHasColor) { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::ColorEdit4("##value_preview", const_cast(glm::value_ptr(m_cacheColor)), ImGuiColorEditFlags_NoInputs); + ImGui::PopItemFlag(); + ImGui::SameLine(); } - } - - return m_cacheExists; - }; - editor->OnExpressionHover = [&](TextEditor* ed, const std::string& id) { - ImGui::Text(id.c_str()); - ImGui::Separator(); - if (m_cacheHasColor) { - ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); - ImGui::ColorEdit4("##value_preview", const_cast(glm::value_ptr(m_cacheColor)), ImGuiColorEditFlags_NoInputs); - ImGui::PopItemFlag(); - ImGui::SameLine(); - } - ImGui::Text(m_cacheValue.c_str()); - }; + ImGui::Text(m_cacheValue.c_str()); + }; + } // copy preview camera info to vertex watch camera & geometry shader output camera if (!Settings::Instance().Project.FPCamera) { diff --git a/src/SHADERed/UI/PixelInspectUI.h b/src/SHADERed/UI/PixelInspectUI.h index b1133aca..6b5ab821 100644 --- a/src/SHADERed/UI/PixelInspectUI.h +++ b/src/SHADERed/UI/PixelInspectUI.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include namespace ed { @@ -18,7 +19,7 @@ namespace ed { void RenderPixelInfo(PixelInformation& pixel, float& elementHeight); - void StartDebugging(TextEditor* editor, PixelInformation* pixel); + void StartDebugging(TextEditor* editor, const PluginShaderEditor& pluginEditor, PixelInformation* pixel); private: std::string m_cacheExpression;