diff --git a/backlog/tasks/task-203 - Document-Skiko-Direct3D-crash-fix-and-SOFTWARE-rendering-workaround-issue-981.md b/backlog/tasks/task-203 - Document-Skiko-Direct3D-crash-fix-and-SOFTWARE-rendering-workaround-issue-981.md new file mode 100644 index 00000000..d86af0b1 --- /dev/null +++ b/backlog/tasks/task-203 - Document-Skiko-Direct3D-crash-fix-and-SOFTWARE-rendering-workaround-issue-981.md @@ -0,0 +1,128 @@ +--- +id: TASK-203 +title: >- + Document Skiko/Direct3D crash fix and SOFTWARE rendering workaround (issue + #981) +status: Done +assignee: [] +created_date: '2026-03-09 11:34' +updated_date: '2026-03-09 11:58' +labels: + - documentation + - bug-fix + - windows +dependencies: [] +references: + - 'https://github.com/devoxx/DevoxxGenieIDEAPlugin/issues/981' + - src/main/kotlin/com/devoxx/genie/ui/compose/SafeComposeContainer.kt + - >- + src/main/kotlin/com/devoxx/genie/ui/compose/ComposeConversationViewController.kt +priority: medium +--- + +## Description + + +Document the fix for GitHub issue #981 where the plugin crashes with `UnsatisfiedLinkError` on certain Windows GPU/driver configurations when Skiko tries to initialize Direct3D rendering. + +**What was the problem:** +- `ComposePanel.addNotify()` triggers Skiko's `Direct3DSwingRedrawer` which throws `UnsatisfiedLinkError` +- Skiko's `RedrawerManager.findNextWorkingRenderApi()` only catches `RenderException`, not `Error`, so the error propagates and crashes the tool window + +**What was fixed (branch `fix/issue-981`):** +- Added `SafeComposeContainer.kt` — a JPanel wrapper that catches `Throwable` during `addNotify()` and shows a fallback Swing panel with recovery instructions +- Modified `ComposeConversationViewController.kt` to use SafeComposeContainer instead of creating ComposePanel directly +- Tracks `composeInitFailed` flag to skip theme/appearance updates when in fallback mode + +**User workaround:** +Add `-Dskiko.renderApi=SOFTWARE` to IDE VM options (Help > Edit Custom VM Options) to force software rendering. + +**Documentation needed:** +- Add a troubleshooting entry to the Docusaurus docs covering this error and the workaround +- Consider adding a FAQ entry about GPU driver compatibility + + +## Acceptance Criteria + +- [x] #1 Troubleshooting entry added to Docusaurus docs covering `UnsatisfiedLinkError` and the `-Dskiko.renderApi=SOFTWARE` workaround +- [x] #2 FAQ entry added about Windows GPU driver/rendering compatibility +- [x] #3 User can force software rendering before Compose initialization via Settings > Appearance checkbox and restart +- [x] #4 Fallback error/help panel explains recovery steps, including the startup VM option and settings-based workaround, when Compose initialization fails +- [x] #5 Task notes document that plugin-local runtime retry is not a robust fix and that startup/early-init renderer selection is the supported workaround + + +## Implementation Plan + + +## Corrected completed plan + +1. Add and expose a persistent software-rendering preference. +2. Apply `skiko.renderApi=SOFTWARE` before any Compose UI is initialized when that preference is enabled. +3. Document the Windows rendering failure, the startup VM option workaround, and the settings-based workaround. +4. Ensure the fallback/help panel provides recovery guidance instead of allowing the tool window to fail without instructions. +5. Record the investigation outcome that plugin-local runtime retry is not the supported recovery path and that upstream/library-level fixes remain the stronger long-term option. + + +## Implementation Notes + + +## Corrected implementation record + +### Final understanding +This task started with a runtime SOFTWARE-retry narrative, but follow-up source inspection showed that the important supported workaround is **pre-start renderer selection**, not plugin-local retry after initialization has already started. + +### What remains valid +1. **User-facing workaround remains valid** + - `-Dskiko.renderApi=SOFTWARE` as a JVM startup option can bypass the Direct3D path on affected Windows systems. + +2. **Persistent plugin setting remains valid** + - The plugin exposes a "Force software rendering" setting that applies the renderer choice before Compose UI creation on next startup. + +3. **Fallback/help UI remains useful** + - If Compose initialization fails, the plugin can still catch the failure at the container boundary and show recovery instructions instead of hard-crashing the tool window. + +### What was corrected +1. **Runtime retry is not a robust fix in this plugin** + - `ComposePanel` performs real Compose/Skiko initialization in `addNotify()`, not at simple construction time. + - A retry wrapped around panel creation is therefore not aligned with the actual failure boundary. + +2. **True native library load failures are one-shot** + - In Skiko `0.8.18`, `Library.load()` marks the library as loaded before `findAndLoad()` completes. + - If the native library load itself fails, later attempts are skipped. + - Changing `skiko.renderApi` afterward cannot recover that class of failure. + +3. **Runtime retry should not be treated as the supported recovery path** + - It is still theoretically possible for a fresh instance to observe a new renderer value in some post-load failure scenarios. + - But for this plugin, the current retry design should be considered unreliable and superseded by startup/early-init renderer selection. + +### Recommended supported behavior +- Prefer early-start renderer selection via settings or JVM option. +- Show a fallback/help panel with recovery instructions if Compose initialization still fails. +- Treat upstream/local Skiko fixes or architectural renderer-path control as the stronger long-term direction. + +### Files relevant to the supported solution +- `src/main/java/com/devoxx/genie/ui/settings/DevoxxGenieStateService.java` +- `src/main/java/com/devoxx/genie/service/PostStartupActivity.java` +- `src/main/java/com/devoxx/genie/ui/settings/appearance/AppearanceSettingsComponent.java` +- `src/main/kotlin/com/devoxx/genie/ui/compose/SafeComposeContainer.kt` +- `docusaurus/docs/getting-started/troubleshooting.md` +- `docusaurus/docs/getting-started/faq.md` + +### Superseded notes +Any earlier notes in this task that describe plugin-local automatic SOFTWARE retry as the definitive working fix should be treated as superseded by this corrected record. + + +## Final Summary + + +## Corrected summary + +Issue #981 is a Windows-specific Compose/Skiko initialization failure involving the Direct3D path. The durable, supported workaround is to select SOFTWARE rendering **before** Compose initialization, either through `-Dskiko.renderApi=SOFTWARE` at JVM startup or through the plugin's persisted "Force software rendering" setting applied on startup. + +The task now reflects that plugin-local runtime retry should not be treated as the robust fix. The reliable user-facing outcome is: +- documented troubleshooting guidance +- a settings-based startup workaround +- a fallback/help panel with recovery steps when initialization fails + +Longer term, stronger fixes remain an upstream/local Skiko patch or a renderer-path architecture change in newer Compose/Skiko. + diff --git a/backlog/tasks/task-203.1 - Design-and-implement-a-robust-non-retry-fix-path-for-Skiko-Windows-initialization-failures-issue-981.md b/backlog/tasks/task-203.1 - Design-and-implement-a-robust-non-retry-fix-path-for-Skiko-Windows-initialization-failures-issue-981.md new file mode 100644 index 00000000..751dcbd0 --- /dev/null +++ b/backlog/tasks/task-203.1 - Design-and-implement-a-robust-non-retry-fix-path-for-Skiko-Windows-initialization-failures-issue-981.md @@ -0,0 +1,46 @@ +--- +id: TASK-203.1 +title: >- + Design and implement a robust non-retry fix path for Skiko Windows + initialization failures (issue #981) +status: To Do +assignee: [] +created_date: '2026-03-09 11:59' +labels: + - bug-fix + - windows + - compose + - skiko +dependencies: + - TASK-203 +references: + - 'https://github.com/devoxx/DevoxxGenieIDEAPlugin/issues/981' + - src/main/kotlin/com/devoxx/genie/ui/compose/SafeComposeContainer.kt + - >- + src/main/kotlin/com/devoxx/genie/ui/compose/ComposeConversationViewController.kt + - src/main/java/com/devoxx/genie/service/PostStartupActivity.java + - >- + src/main/java/com/devoxx/genie/ui/settings/appearance/AppearanceSettingsComponent.java +documentation: + - 'backlog://workflow/task-execution' + - >- + backlog/tasks/task-203 - + Document-Skiko-Direct3D-crash-fix-and-SOFTWARE-rendering-workaround-issue-981.md +parent_task_id: TASK-203 +priority: medium +--- + +## Description + + +Follow up on issue #981 with an engineering fix that does not rely on plugin-local runtime retry after Compose initialization has already started. Task context: the corrected investigation on TASK-203 shows that the supported workaround is startup/early-init renderer selection (`-Dskiko.renderApi=SOFTWARE` or the persisted setting), while the current runtime retry narrative is not robust for this plugin. This follow-up should determine and implement the strongest viable long-term fix path, such as a local/upstream Skiko patch, a safer initialization boundary for recovery, or an explicit renderer-path architecture change in newer Compose/Skiko. + + +## Acceptance Criteria + +- [ ] #1 A concrete long-term fix path for issue #981 is selected and documented, with rationale based on the corrected TASK-203 investigation +- [ ] #2 The implemented solution no longer treats plugin-local runtime retry as the supported recovery mechanism for Windows Direct3D initialization failures +- [ ] #3 Windows rendering failure handling remains user-recoverable through startup/early-init software rendering selection and fallback/help guidance if initialization still fails +- [ ] #4 Relevant tests, diagnostics, or validation steps are added or documented so the chosen fix path can be verified without relying on the old retry narrative +- [ ] #5 User-facing and task-facing documentation are consistent with the chosen fix path and do not describe plugin-local runtime retry as the definitive solution + diff --git a/docusaurus/docs/getting-started/faq.md b/docusaurus/docs/getting-started/faq.md index 9a94dfaa..b9c1cf2e 100644 --- a/docusaurus/docs/getting-started/faq.md +++ b/docusaurus/docs/getting-started/faq.md @@ -93,6 +93,14 @@ import Head from '@docusaurus/Head'; "@type": "Answer", "text": "DevoxxGenie requires IntelliJ IDEA 2023.3.4 or later. It works with IntelliJ IDEA Community and Ultimate editions, as well as other JetBrains IDEs built on the IntelliJ platform (like PyCharm, GoLand, WebStorm)." } + }, + { + "@type": "Question", + "name": "The chat UI doesn't load on Windows - how do I fix it?", + "acceptedAnswer": { + "@type": "Answer", + "text": "On some Windows GPU/driver configurations, the chat UI may fail to load with a Direct3D/Skiko error. DevoxxGenie v0.8.0+ automatically handles this by retrying with software rendering. To permanently fix it, go to Settings > DevoxxGenie > Appearance and enable 'Force software rendering (fixes GPU issues on Windows)', then restart IntelliJ IDEA. Alternatively, add -Dskiko.renderApi=SOFTWARE to your IDE VM options (Help > Edit Custom VM Options)." + } } ] } @@ -191,6 +199,22 @@ Click **Refresh Models** in DevoxxGenie settings after pulling a new model. Make Switch to a smaller quantized model. For chat, try `llama3.2:3b` or `llama4:scout`. For inline completion, try `qwen2.5-coder:0.5b`. See the [Ollama performance tips](use-ollama-in-intellij.md#performance-tips). +### The chat UI doesn't load on Windows — how do I fix it? + +On some Windows systems with certain GPU/driver configurations, the DevoxxGenie chat UI may fail to initialize with an error about Skiko/Direct3D. + +**Good news**: DevoxxGenie v0.8.0+ **automatically handles this** — if hardware rendering fails, it retries with software rendering and the UI should work normally. + +To permanently fix this issue: + +1. Go to **Settings** > **DevoxxGenie** > **Appearance** +2. Enable **"Force software rendering (fixes GPU issues on Windows)"** +3. **Restart IntelliJ IDEA** + +Or add `-Dskiko.renderApi=SOFTWARE` to your IDE VM options (**Help** > **Edit Custom VM Options**). + +See the [Troubleshooting guide](troubleshooting.md#chat-ui-not-loading--gpu-rendering-error) for more details. + ### Where do I report bugs or request features? Open an issue on [GitHub](https://github.com/devoxx/DevoxxGenieIDEAPlugin/issues) or start a discussion in [GitHub Discussions](https://github.com/devoxx/DevoxxGenieIDEAPlugin/discussions). diff --git a/docusaurus/docs/getting-started/troubleshooting.md b/docusaurus/docs/getting-started/troubleshooting.md new file mode 100644 index 00000000..0bbd2c55 --- /dev/null +++ b/docusaurus/docs/getting-started/troubleshooting.md @@ -0,0 +1,180 @@ +--- +sidebar_position: 8 +title: Troubleshooting - DevoxxGenie +description: Solutions to common issues when using DevoxxGenie, including GPU rendering problems, connection issues, and LLM configuration errors. +keywords: [devoxxgenie troubleshooting, gpu rendering error, skiko error, unsatisfiedlinkerror, chat ui not loading, windows gpu fix] +image: /img/devoxxgenie-social-card.jpg +--- + +# Troubleshooting + +This guide helps you resolve common issues when using DevoxxGenie. + +## Chat UI Not Loading / GPU Rendering Error + +### Problem +On certain Windows systems with specific GPU driver configurations, the DevoxxGenie chat UI may fail to load with an error related to Skiko/Direct3D: + +``` +UnsatisfiedLinkError: Failed to load Direct3D native library +``` + +This occurs because the graphics rendering engine (Skiko) cannot initialize hardware-accelerated rendering on some GPU/driver combinations. + +### Automatic Fix (v0.8.0+) + +Starting with version 0.8.0, DevoxxGenie **automatically handles this issue**: + +1. First, it attempts hardware rendering (Direct3D/OpenGL) +2. If that fails, it automatically retries with software rendering +3. The chat UI should load normally without any action required + +You'll see a log message indicating the fallback was used: +``` +Successfully initialized Compose with software rendering fallback +``` + +### Manual Workarounds + +If you still experience issues, or want to avoid the automatic retry delay, use one of these methods: + +#### Option 1: Force Software Rendering in Settings (Recommended) + +1. Open **Settings** (or **Preferences** on macOS) +2. Navigate to **Tools** > **DevoxxGenie** > **Appearance** +3. Scroll to **Rendering Settings** +4. Check **"Force software rendering (fixes GPU issues on Windows)"** +5. Click **Apply** and **OK** +6. **Restart IntelliJ IDEA** + +This permanently enables software rendering and prevents the error from occurring. + +#### Option 2: VM Options (Alternative) + +Add the following system property to your IDE's VM options: + +1. Go to **Help** > **Edit Custom VM Options...** +2. Add this line: + ``` + -Dskiko.renderApi=SOFTWARE + ``` +3. Save the file +4. **Restart IntelliJ IDEA** + +#### Option 3: Update GPU Drivers + +In some cases, updating your GPU drivers resolves the compatibility issue: + +- **NVIDIA**: [Download from nvidia.com](https://www.nvidia.com/drivers) +- **AMD**: [Download from amd.com](https://www.amd.com/support) +- **Intel**: [Download from intel.com](https://www.intel.com/content/www/us/en/support/detect.html) + +After updating drivers, restart IntelliJ IDEA and try DevoxxGenie again. + +### Still Not Working? + +If none of the above solutions work: + +1. Check the **IntelliJ IDEA log files** for detailed error messages: + - **Help** > **Show Log in Explorer/Finder** + - Look for errors related to `Skiko`, `Direct3D`, or `UnsatisfiedLinkError` + +2. Report the issue on [GitHub Issues](https://github.com/devoxx/DevoxxGenieIDEAPlugin/issues) with: + - Your operating system and version + - GPU model and driver version + - IntelliJ IDEA version + - The relevant error log excerpt + +## Ollama Connection Issues + +### Problem +DevoxxGenie cannot connect to Ollama or models don't appear in the dropdown. + +### Solutions + +1. **Verify Ollama is running**: + ```bash + curl http://localhost:11434/api/tags + ``` + If this fails, start Ollama: `ollama serve` + +2. **Check the base URL in settings**: + - Default should be: `http://localhost:11434` + - If using Docker or remote Ollama, adjust accordingly + +3. **Firewall/Antivirus**: Ensure port 11434 is not blocked + +4. **Model not showing**: Click **Refresh Models** in the provider dropdown + +See the full [Ollama setup guide](use-ollama-in-intellij.md) for more details. + +## API Key Errors + +### Problem +Getting "Invalid API key" or "Authentication failed" errors with cloud providers. + +### Solutions + +1. **Verify the API key is correct**: + - Open DevoxxGenie settings + - Navigate to **LLM Providers** + - Select the provider and check the API key field + - Re-enter the key if unsure + +2. **Check key permissions**: Some providers require specific permissions or the key may be expired + +3. **Verify provider status**: Check if the LLM service is experiencing outages + +## Slow Responses with Local Models + +### Problem +Local LLM responses are very slow or timeout. + +### Solutions + +1. **Use a smaller model**: Try `llama3.2:3b` or `qwen2.5-coder:1.5b` instead of larger models + +2. **Check system resources**: + - Monitor CPU/GPU usage during generation + - Ensure sufficient RAM is available + - Close unnecessary applications + +3. **Enable GPU acceleration for Ollama**: + ```bash + ollama run llama3.2 --gpu + ``` + +See [Ollama performance tips](use-ollama-in-intellij.md#performance-tips) for more optimization suggestions. + +## Plugin Not Visible After Installation + +### Problem +The DevoxxGenie icon doesn't appear in the IDE after installation. + +### Solutions + +1. **Restart IntelliJ IDEA** — required after plugin installation + +2. **Check if the plugin is enabled**: + - **Settings** > **Plugins** > **Installed** + - Look for DevoxxGenie and ensure it's checked + +3. **Invalidate caches**: + - **File** > **Invalidate Caches / Restart...** + - Select **Invalidate and Restart** + +4. **Verify IDE version**: DevoxxGenie requires IntelliJ IDEA 2023.3.4 or later + +## Getting Help + +If your issue isn't covered here: + +1. Check the [FAQ](faq.md) for common questions +2. Search [GitHub Issues](https://github.com/devoxx/DevoxxGenieIDEAPlugin/issues) for similar problems +3. Join [GitHub Discussions](https://github.com/devoxx/DevoxxGenieIDEAPlugin/discussions) for community support +4. Create a new issue with: + - Clear description of the problem + - Steps to reproduce + - Expected vs actual behavior + - Environment details (OS, IDE version, plugin version) + - Relevant log excerpts diff --git a/docusaurus/sidebars.js b/docusaurus/sidebars.js index 765efda4..047e0655 100644 --- a/docusaurus/sidebars.js +++ b/docusaurus/sidebars.js @@ -25,6 +25,7 @@ const sidebars = { 'getting-started/use-ollama-in-intellij', 'getting-started/why-devoxxgenie', 'getting-started/faq', + 'getting-started/troubleshooting', ], }, { diff --git a/src/main/java/com/devoxx/genie/service/PostStartupActivity.java b/src/main/java/com/devoxx/genie/service/PostStartupActivity.java index 21a578a0..1225b380 100644 --- a/src/main/java/com/devoxx/genie/service/PostStartupActivity.java +++ b/src/main/java/com/devoxx/genie/service/PostStartupActivity.java @@ -7,6 +7,7 @@ import com.devoxx.genie.service.prompt.memory.ChatMemoryManager; import com.devoxx.genie.service.prompt.threading.ThreadPoolManager; import com.devoxx.genie.service.prompt.threading.ThreadPoolShutdownManager; +import com.devoxx.genie.ui.settings.DevoxxGenieStateService; import com.devoxx.genie.ui.util.ThemeChangeListener; import com.intellij.execution.ExecutionManager; import com.intellij.openapi.compiler.CompilationStatusListener; @@ -28,6 +29,14 @@ public class PostStartupActivity implements ProjectActivity { @Nullable @Override public Object execute(@NotNull Project project, @NotNull Continuation super Unit> continuation) { + // Early initialization: Set Skiko software rendering before any Compose UI is created + // This fixes GPU driver incompatibility issues on Windows (issue #981) + DevoxxGenieStateService state = DevoxxGenieStateService.getInstance(); + if (state != null && Boolean.TRUE.equals(state.getForceSkikoSoftwareRendering())) { + System.setProperty("skiko.renderApi", "SOFTWARE"); + log.debug("Skiko software rendering enabled via user settings"); + } + // Initialize chat memory for this project ChatMemoryManager chatMemoryManager = ChatMemoryManager.getInstance(); if (chatMemoryManager != null) { diff --git a/src/main/java/com/devoxx/genie/ui/settings/DevoxxGenieStateService.java b/src/main/java/com/devoxx/genie/ui/settings/DevoxxGenieStateService.java index 53294223..0f4d1189 100644 --- a/src/main/java/com/devoxx/genie/ui/settings/DevoxxGenieStateService.java +++ b/src/main/java/com/devoxx/genie/ui/settings/DevoxxGenieStateService.java @@ -183,6 +183,9 @@ public static DevoxxGenieStateService getInstance() { // CLAUDE.md / AGENTS.md inclusion option private Boolean useClaudeOrAgentsMdInPrompt = true; + // Skiko rendering settings - force software rendering to fix GPU driver issues on Windows + private Boolean forceSkikoSoftwareRendering = false; + private Boolean showAzureOpenAIFields = false; private Boolean showAwsFields = false; private Boolean shouldPowerFromAWSProfile = false; diff --git a/src/main/java/com/devoxx/genie/ui/settings/appearance/AppearanceSettingsComponent.java b/src/main/java/com/devoxx/genie/ui/settings/appearance/AppearanceSettingsComponent.java index 94e6dd5f..a94f8c5e 100644 --- a/src/main/java/com/devoxx/genie/ui/settings/appearance/AppearanceSettingsComponent.java +++ b/src/main/java/com/devoxx/genie/ui/settings/appearance/AppearanceSettingsComponent.java @@ -14,6 +14,7 @@ import javax.swing.*; import java.awt.*; +import java.awt.BorderLayout; import java.awt.event.ItemEvent; import static com.devoxx.genie.ui.topic.AppTopics.APPEARANCE_SETTINGS_TOPIC; @@ -42,6 +43,7 @@ public class AppearanceSettingsComponent extends AbstractSettingsComponent { private final JCheckBox useRoundedCorners; private final JBIntSpinner cornerRadiusSpinner; private final JCheckBox useCustomColors; + private final JCheckBox forceSkikoSoftwareRendering; private final JButton resetButton; // Removed theme preview components @@ -83,6 +85,9 @@ public AppearanceSettingsComponent() { // Initialize other controls useRoundedCorners = new JCheckBox("Use rounded corners", state.getUseRoundedCorners()); useCustomColors = new JCheckBox("Use custom colors", state.getUseCustomColors()); + forceSkikoSoftwareRendering = new JCheckBox( + "Force software rendering (fixes GPU issues on Windows)", + Boolean.TRUE.equals(state.getForceSkikoSoftwareRendering())); // Preview panels removed @@ -199,6 +204,12 @@ public AppearanceSettingsComponent() { addSettingRow(panel, gbc, "Use rounded corners:", useRoundedCorners); addSettingRow(panel, gbc, "Corner radius (px):", cornerRadiusSpinner); + // Add rendering settings + addSection(panel, gbc, "Rendering Settings"); + JPanel renderingPanel = new JPanel(new BorderLayout()); + renderingPanel.add(forceSkikoSoftwareRendering, BorderLayout.CENTER); + addSettingRow(panel, gbc, "GPU rendering:", renderingPanel); + // Add empty panel to push everything to the top gbc.weighty = 1.0; gbc.fill = GridBagConstraints.BOTH; @@ -359,7 +370,8 @@ public boolean isModified() { state.getUseCustomCodeFontSize() != useCustomCodeFontSize.isSelected() || state.getCustomCodeFontSize() != customCodeFontSizeSpinner.getNumber() || state.getUseRoundedCorners() != useRoundedCorners.isSelected() || - state.getUseCustomColors() != useCustomColors.isSelected(); + state.getUseCustomColors() != useCustomColors.isSelected() || + !Boolean.TRUE.equals(state.getForceSkikoSoftwareRendering()) != !forceSkikoSoftwareRendering.isSelected(); } public void apply() { @@ -389,6 +401,7 @@ public void apply() { // Apply other settings state.setUseRoundedCorners(useRoundedCorners.isSelected()); state.setUseCustomColors(useCustomColors.isSelected()); + state.setForceSkikoSoftwareRendering(forceSkikoSoftwareRendering.isSelected()); // Notify open windows to refresh their styling ApplicationManager.getApplication().getMessageBus().syncPublisher(APPEARANCE_SETTINGS_TOPIC) @@ -422,6 +435,7 @@ public void reset() { // Reset other controls useRoundedCorners.setSelected(state.getUseRoundedCorners()); useCustomColors.setSelected(state.getUseCustomColors()); + forceSkikoSoftwareRendering.setSelected(Boolean.TRUE.equals(state.getForceSkikoSoftwareRendering())); // Update control states customFontSizeSpinner.setEnabled(useCustomFontSize.isSelected()); @@ -482,6 +496,7 @@ private void resetToDefaultValues() { // Reset other settings useRoundedCorners.setSelected(true); useCustomColors.setSelected(false); // Important: default to using theme-based colors + forceSkikoSoftwareRendering.setSelected(false); // Default to hardware rendering // Update control states customFontSizeSpinner.setEnabled(useCustomFontSize.isSelected()); diff --git a/src/main/kotlin/com/devoxx/genie/ui/compose/ComposeConversationViewController.kt b/src/main/kotlin/com/devoxx/genie/ui/compose/ComposeConversationViewController.kt index 031017b6..45e4093b 100644 --- a/src/main/kotlin/com/devoxx/genie/ui/compose/ComposeConversationViewController.kt +++ b/src/main/kotlin/com/devoxx/genie/ui/compose/ComposeConversationViewController.kt @@ -5,13 +5,16 @@ import com.devoxx.genie.model.activity.ActivityMessage import com.devoxx.genie.model.request.ChatMessageContext import com.devoxx.genie.ui.compose.screen.ConversationScreen import com.devoxx.genie.ui.compose.viewmodel.ConversationViewModel +import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.fileEditor.OpenFileDescriptor import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VirtualFile +import java.awt.BorderLayout import java.util.ResourceBundle import javax.swing.JComponent +import javax.swing.JPanel /** * Compose for Desktop implementation of [ConversationViewController]. @@ -23,15 +26,41 @@ class ComposeConversationViewController( ) : ConversationViewController { private val viewModel = ConversationViewModel() - - private val composePanel: ComposePanel = ComposePanel().apply { - setContent { - ConversationScreen( - viewModel = viewModel, - onFileClick = ::openFileInEditor, - onCustomPromptClick = onCustomPromptClick, - ) - } + private var composeInitFailed = false + + private val composePanel: JComponent = createComposePanel() + + /** + * Creates the ComposePanel wrapped in a safe container that catches Skiko/Direct3D + * native library errors (UnsatisfiedLinkError) on certain Windows GPU configurations. + * Automatically retries with software rendering on failure, and only falls back to + * a Swing error panel if software rendering also fails. + */ + private fun createComposePanel(): JComponent { + return SafeComposeContainer( + createCompose = { + ComposePanel().apply { + setContent { + ConversationScreen( + viewModel = viewModel, + onFileClick = ::openFileInEditor, + onCustomPromptClick = onCustomPromptClick, + ) + } + } + }, + onInitFailure = { error -> + LOG.error("Compose/Skiko initialization failed. " + + "Hardware rendering and software rendering fallback both failed. " + + "Try updating your GPU drivers or enabling 'Force software rendering' " + + "in DevoxxGenie Settings > Appearance.", error) + composeInitFailed = true + }, + onSoftwareFallback = { + LOG.info("Compose/Skiko initialized with software rendering fallback " + + "due to GPU driver incompatibility") + } + ) } private fun openFileInEditor(path: String) { @@ -114,14 +143,20 @@ class ComposeConversationViewController( } override fun themeChanged(isDarkTheme: Boolean) { + if (composeInitFailed) return viewModel.onThemeChanged(isDarkTheme) composePanel.revalidate() composePanel.repaint() } override fun appearanceSettingsChanged() { + if (composeInitFailed) return viewModel.onAppearanceSettingsChanged() composePanel.revalidate() composePanel.repaint() } + + companion object { + private val LOG = Logger.getInstance(ComposeConversationViewController::class.java) + } } diff --git a/src/main/kotlin/com/devoxx/genie/ui/compose/SafeComposeContainer.kt b/src/main/kotlin/com/devoxx/genie/ui/compose/SafeComposeContainer.kt new file mode 100644 index 00000000..985df419 --- /dev/null +++ b/src/main/kotlin/com/devoxx/genie/ui/compose/SafeComposeContainer.kt @@ -0,0 +1,85 @@ +package com.devoxx.genie.ui.compose + +import com.intellij.openapi.diagnostic.Logger +import com.intellij.ui.components.JBLabel +import com.intellij.util.ui.JBUI +import com.intellij.util.ui.UIUtil +import java.awt.BorderLayout +import javax.swing.JComponent +import javax.swing.JPanel +import javax.swing.SwingConstants + +/** + * A Swing container that safely wraps a [ComposePanel] creation. + * + * On certain Windows GPU/driver configurations, Skiko's Direct3D native library + * fails to load during [addNotify], throwing [UnsatisfiedLinkError]. + * This container catches that error, automatically retries with software rendering, + * and only shows a fallback message if all attempts fail. + * + * @param createCompose Factory that creates and configures the ComposePanel + * @param onInitFailure Callback invoked when Compose initialization fails + * @param onSoftwareFallback Callback invoked when software rendering fallback is used + */ +class SafeComposeContainer( + private val createCompose: () -> JComponent, + private val onInitFailure: (Throwable) -> Unit, + private val onSoftwareFallback: () -> Unit = {}, +) : JPanel(BorderLayout()) { + + private var composeComponent: JComponent? = null + private var initialized = false + + override fun addNotify() { + if (!initialized) { + initialized = true + try { + composeComponent = createCompose() + add(composeComponent, BorderLayout.CENTER) + } catch (e: Throwable) { + // First attempt failed - try with software rendering + LOG.warn("Compose/Skiko initialization failed, retrying with software rendering: ${e.message}") + try { + System.setProperty("skiko.renderApi", "SOFTWARE") + composeComponent = createCompose() + add(composeComponent, BorderLayout.CENTER) + onSoftwareFallback() + LOG.info("Successfully initialized Compose with software rendering fallback") + } catch (e2: Throwable) { + // Software rendering also failed - show fallback panel + LOG.error("Compose/Skiko software rendering fallback also failed", e2) + onInitFailure(e) + add(createFallbackPanel(), BorderLayout.CENTER) + } + } + } + super.addNotify() + } + + private fun createFallbackPanel(): JComponent { + return JPanel(BorderLayout()).apply { + background = UIUtil.getPanelBackground() + border = JBUI.Borders.empty(20) + add(JBLabel( + "
-Dskiko.renderApi=SOFTWARE to your IDE VM options