Skip to content

Commit c0c561b

Browse files
committed
Merge branch 'develop' of github.com:3dJan/gladius_playground into develop
2 parents fa31180 + 1273687 commit c0c561b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+8166
-625
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
description: 'Planning chat mode.'
3-
tools: ['changes', 'codebase', 'editFiles', 'findTestFiles', 'githubRepo', 'openSimpleBrowser', 'search', 'searchResults', 'usages']
3+
tools: ['edit', 'search', 'usages', 'changes', 'openSimpleBrowser', 'githubRepo']
44
---
55
You are a planning assistant. Your task is to help users outline and organize their ideas, projects, or tasks. You should focus on providing structured guidance, suggesting relevant tools or frameworks, and helping users break down their goals into actionable steps.
66

7-
You store your plans in a structured format in gladius/thegreatplan/. You outline the plan step by step and explain the reasoning behind each step. You can also suggest relevant libraries, frameworks, or tools that can assist in the planning process. When suggesting libs, frameworks, or tools, ensure they are well-documented and widely used in the community. Provide links to their official documentation or repositories when possible. Availability through VCPKG is preferable, but not mandatory.
7+
You store your plans in a structured format in gladius/thegreatplan/. You outline the plan step by step and explain the reasoning behind each step. You can also suggest relevant libraries, frameworks, or tools that can assist in the planning process. When suggesting libs, frameworks, or tools, ensure they are well-documented and widely used in the community. Provide links to their official documentation or repositories when possible. Availability through VCPKG is preferable, but not mandatory. Please do not make any code changes.

.github/copilot-instructions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
- **DRY Principle**: Don't repeat yourself. Avoid code duplication.
1717
- **YAGNI Principle**: You aren't gonna need it. Avoid adding features until they are necessary.
1818
- **Tool usage**: Prefer using tools rather than doing things manually in the terminal.
19+
- **Keep files small**: Prefer smaller files (e.g., <400 lines) for better readability and maintainability.
1920

2021
## Code Structure
2122
- **Headers**: Use `.h` for declarations, `.cpp` for definitions.

.github/workflows/build.yml

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,15 @@ on:
1212
workflow_dispatch:
1313
workflow_call: # Allow this workflow to be called by other workflows
1414

15+
permissions:
16+
packages: write # Required for vcpkg binary caching with GitHub Packages
17+
1518
jobs:
1619
build:
1720
runs-on: ${{ matrix.os }}
21+
22+
env:
23+
VCPKG_BINARY_SOURCES: "clear;nuget,https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json,readwrite"
1824

1925
strategy:
2026
# Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable.
@@ -89,6 +95,75 @@ jobs:
8995
run: ./bootstrap-vcpkg.bat
9096
working-directory: ${{ github.workspace }}/vcpkg
9197

98+
- name: Install mono for NuGet (Linux)
99+
if: runner.os != 'Windows'
100+
run: sudo apt-get install -y mono-complete
101+
102+
- name: Install buildcache (Linux)
103+
if: runner.os != 'Windows'
104+
run: |
105+
wget https://github.com/mbitsnbites/buildcache/releases/download/v0.28.1/buildcache-linux.tar.gz
106+
tar -xzf buildcache-linux.tar.gz
107+
sudo cp buildcache/bin/buildcache /usr/local/bin/
108+
buildcache --version
109+
110+
- name: Install buildcache (Windows)
111+
if: runner.os == 'Windows'
112+
shell: pwsh
113+
run: |
114+
Invoke-WebRequest -Uri "https://github.com/mbitsnbites/buildcache/releases/download/v0.28.1/buildcache-windows.zip" -OutFile "buildcache.zip"
115+
Expand-Archive -Path "buildcache.zip" -DestinationPath "buildcache" -Force
116+
Copy-Item -Path "buildcache\buildcache\bin\buildcache.exe" -Destination "C:\Windows\System32\buildcache.exe" -Force
117+
buildcache --version
118+
119+
- name: Cache buildcache (Linux)
120+
if: runner.os != 'Windows'
121+
uses: actions/cache@v4
122+
with:
123+
path: ~/.buildcache
124+
key: buildcache-${{ matrix.os }}-${{ matrix.c_compiler }}-${{ github.sha }}
125+
restore-keys: |
126+
buildcache-${{ matrix.os }}-${{ matrix.c_compiler }}-
127+
128+
- name: Cache buildcache (Windows)
129+
if: runner.os == 'Windows'
130+
uses: actions/cache@v4
131+
with:
132+
path: ~\AppData\Local\buildcache
133+
key: buildcache-${{ matrix.os }}-${{ matrix.c_compiler }}-${{ github.sha }}
134+
restore-keys: |
135+
buildcache-${{ matrix.os }}-${{ matrix.c_compiler }}-
136+
137+
- name: Setup NuGet authentication for vcpkg binary caching (Linux)
138+
if: runner.os != 'Windows'
139+
shell: bash
140+
run: |
141+
mono `${{ github.workspace }}/vcpkg/vcpkg fetch nuget | tail -n 1` \
142+
sources add \
143+
-Source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" \
144+
-StorePasswordInClearText \
145+
-Name GitHubPackages \
146+
-UserName "${{ github.repository_owner }}" \
147+
-Password "${{ secrets.GITHUB_TOKEN }}"
148+
mono `${{ github.workspace }}/vcpkg/vcpkg fetch nuget | tail -n 1` \
149+
setapikey "${{ secrets.GITHUB_TOKEN }}" \
150+
-Source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json"
151+
152+
- name: Setup NuGet authentication for vcpkg binary caching (Windows)
153+
if: runner.os == 'Windows'
154+
shell: pwsh
155+
run: |
156+
& "$(${{ github.workspace }}/vcpkg/vcpkg fetch nuget)" `
157+
sources add `
158+
-Source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" `
159+
-StorePasswordInClearText `
160+
-Name GitHubPackages `
161+
-UserName "${{ github.repository_owner }}" `
162+
-Password "${{ secrets.GITHUB_TOKEN }}"
163+
& "$(${{ github.workspace }}/vcpkg/vcpkg fetch nuget)" `
164+
setapikey "${{ secrets.GITHUB_TOKEN }}" `
165+
-Source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json"
166+
92167
- name: Set reusable strings
93168
# Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file.
94169
id: strings
@@ -104,6 +179,7 @@ jobs:
104179
-DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}
105180
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
106181
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
182+
-DUSE_CACHE=ON
107183
-G Ninja
108184
-S ${{ github.workspace }}/gladius
109185
env:

gladius/CMakePresets.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@
108108
"USE_CACHE": "true",
109109
"VCPKG_OVERLAY_PORTS": "${sourceDir}/vcpkg-overlay-ports",
110110
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
111-
"ENABLE_COVERAGE": "OFF"
111+
"ENABLE_COVERAGE": "OFF",
112+
"ENABLE_TRACY": "TRUE"
112113
}
113114
},
114115
{

gladius/src/CLProgram.h

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,11 @@ namespace gladius
9494
void finishCompilation();
9595

9696
template <typename... ArgumentTypes>
97-
void runNonBlocking(cl::CommandQueue const & queue,
98-
const std::string & methodName,
99-
cl::NDRange origin,
100-
cl::NDRange range,
101-
const ArgumentTypes &... args)
97+
[[nodiscard]] cl::Event runNonBlocking(cl::CommandQueue const & queue,
98+
const std::string & methodName,
99+
cl::NDRange origin,
100+
cl::NDRange range,
101+
const ArgumentTypes &... args)
102102
{
103103
ProfileFunction;
104104

@@ -139,7 +139,7 @@ namespace gladius
139139
if (!isValid())
140140
{
141141
logError("Program not valid - returning");
142-
return;
142+
return cl::Event{};
143143
}
144144
std::scoped_lock lock(m_compilationMutex);
145145

@@ -263,16 +263,19 @@ namespace gladius
263263
throw;
264264
}
265265

266+
cl::Event kernelEvent;
266267
try
267268
{
268269
CL_ERROR(
269-
queue.enqueueNDRangeKernel(m_kernels[methodName], origin, range, cl::NullRange));
270+
queue.enqueueNDRangeKernel(m_kernels[methodName], origin, range, cl::NullRange, nullptr, &kernelEvent));
270271
}
271272
catch (const OpenCLError & e)
272273
{
273274
logError("Kernel enqueue failed", e.what());
274275
throw;
275276
}
277+
278+
return kernelEvent;
276279
}
277280

278281
template <typename... ArgumentTypes>
@@ -329,16 +332,11 @@ namespace gladius
329332

330333
try
331334
{
332-
runNonBlocking(queue, methodName, origin, range, args...);
333-
}
334-
catch (const std::exception & e)
335-
{
336-
logError("RunNonBlocking failed", e.what());
337-
throw;
338-
}
339-
340-
try
341-
{
335+
cl::Event const event = runNonBlocking(queue, methodName, origin, range, args...);
336+
if (event())
337+
{
338+
event.wait();
339+
}
342340
CL_ERROR(queue.finish());
343341
}
344342
catch (const OpenCLError & e)
@@ -347,6 +345,11 @@ namespace gladius
347345

348346
throw;
349347
}
348+
catch (const std::exception & e)
349+
{
350+
logError("RunNonBlocking failed", e.what());
351+
throw;
352+
}
350353
}
351354

352355
template <typename... ArgumentTypes>

gladius/src/ComputeContext.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ namespace gladius
8080

8181
[[nodiscard]] const cl::CommandQueue & GetQueue();
8282

83+
/// @brief Create a new OpenCL command queue for the current context
84+
/// @return A new command queue
85+
cl::CommandQueue createQueue() const;
86+
8387
[[nodiscard]] bool isValid() const;
8488

8589
[[nodiscard]] const cl::Device & GetDevice() const;
@@ -196,7 +200,6 @@ namespace gladius
196200
void checkMemoryLayoutConflicts(const std::string & operationName) const;
197201

198202
private:
199-
cl::CommandQueue createQueue() const;
200203
void initContext();
201204
void queryDeviceMemoryCaps();
202205
bool tryQueryVendorFreeMem(size_t & freeBytesOut) const; // best-effort

gladius/src/Document.cpp

Lines changed: 87 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,66 @@ namespace gladius
139139
updateFlatAssembly();
140140

141141
m_core->refreshProgram(m_flatAssembly);
142-
m_core->recompileBlockingNoLock();
143-
m_core->invalidatePreCompSdf();
142+
143+
// Use non-blocking compilation with polling
144+
m_core->recompileIfRequired();
145+
146+
// Wait for compilation to complete with periodic checks
147+
while (m_core->isCompilationInProgress())
148+
{
149+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
150+
}
151+
152+
// One more pass ensures ProgramManager updates its internal ModelState flags
153+
// (signalCompilationFinished) so subsequent steps observe up-to-date slicer state.
154+
m_core->recompileIfRequired();
155+
156+
// Don't invalidate SDF - let it stay valid during recomputation to avoid flicker
157+
// The async computation will atomically replace it
144158
m_core->resetBoundingBox();
145-
if (m_core->precomputeSdfForWholeBuildPlatform())
159+
160+
// Launch async SDF precomputation with OpenCL events
161+
auto const & queue = m_core->getComputeContext()->GetQueue();
162+
cl::Event sdfEvent = m_core->precomputeSdfAsync(queue);
163+
bool const sdfEventValid = sdfEvent() != nullptr;
164+
165+
bool sdfUpdated = false;
166+
bool sdfUpdatedViaAsync = false;
167+
168+
// Wait for SDF computation to complete (non-blocking on CPU, async on GPU)
169+
if (sdfEventValid)
170+
{
171+
sdfEvent.wait();
172+
sdfUpdated = true;
173+
sdfUpdatedViaAsync = true;
174+
}
175+
else
176+
{
177+
// Fallback to synchronous computation if async launch failed
178+
if (m_core->precomputeSdfForWholeBuildPlatform())
179+
{
180+
sdfUpdated = true;
181+
}
182+
else
183+
{
184+
}
185+
}
186+
187+
if (sdfUpdated)
146188
{
147-
meshResourceState->signalCompilationFinished();
189+
m_core->setSdfValid(true);
190+
if (sdfUpdatedViaAsync)
191+
{
192+
// Now that the SDF exists, update the bounding box serially (still off the UI thread)
193+
m_core->updateBBox();
194+
}
148195
}
196+
else
197+
{
198+
m_core->invalidatePreCompSdf("refreshWorkerFailure");
199+
}
200+
201+
meshResourceState->signalCompilationFinished();
149202
}
150203

151204
void Document::updateFlatAssembly()
@@ -334,18 +387,43 @@ namespace gladius
334387

335388
updatePayload();
336389

390+
// Check if we can use the fast path (parameter structure unchanged)
391+
bool const canUseFastPath = m_core->isParameterSignatureCompatible(*m_assembly);
392+
393+
auto attemptParameterUpdate = [&]() -> bool
337394
{
338-
m_parameterDirty = m_core->tryToupdateParameter(*m_assembly);
339-
}
395+
if (!m_core->tryToupdateParameter(*m_assembly))
396+
{
397+
return false;
398+
}
399+
return true;
400+
};
340401

341-
if (m_parameterDirty)
402+
bool updateSucceeded = false;
403+
404+
if (canUseFastPath)
342405
{
343-
m_parameterDirty = !m_core->precomputeSdfForWholeBuildPlatform();
406+
updateSucceeded = attemptParameterUpdate();
344407
}
345408
else
346409
{
347-
m_parameterDirty = true;
410+
// Slow path: parameter structure changed
411+
// NOTE: We don't call refreshModelAsync() here because updateParameter()
412+
// is often called FROM WITHIN refreshWorker(), which would cause recursion.
413+
// Instead, we just update normally and let the signature be recaptured
414+
// on the next full refresh cycle.
415+
auto logger = getSharedLogger();
416+
if (logger)
417+
{
418+
logger->addEvent(
419+
{"Parameter structure mismatch detected (will be updated on next refresh)",
420+
events::Severity::Info});
421+
}
422+
423+
updateSucceeded = attemptParameterUpdate();
348424
}
425+
426+
m_parameterDirty = !updateSucceeded;
349427
}
350428

351429
void Document::updateParameterRegistration()

gladius/src/Profiling.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
#include <thread>
77
#include <tracy/Tracy.hpp>
88

9+
// Enable debug output for async rendering diagnostics
10+
//#define ASYNC_DEBUG_OUTPUT
11+
912
namespace gladius
1013
{
1114
class ScopedProfilingFrame
@@ -30,6 +33,16 @@ namespace gladius
3033
// #define LOG_LOCATION std::cout << "Method: " << __FUNCTION__ << " line: " << __LINE__ << ",
3134
// Thread ID: " << std::this_thread::get_id() << std::endl; #define ProfileFunction ZoneScoped;
3235

36+
#ifdef ASYNC_DEBUG_OUTPUT
37+
/// For debugging: prints text to console instead of Tracy
38+
#define DebugText(text, len) std::cout << "[" << std::this_thread::get_id() << "] " << text << std::endl
39+
#define DebugValue(value) std::cout << "[" << std::this_thread::get_id() << "] " << #value << " = " << value << std::endl
40+
#else
41+
/// For profiling: sends text to Tracy
42+
#define DebugText(text, len) ZoneText(text, len)
43+
#define DebugValue(value) ZoneValue(value)
44+
#endif
45+
3346
class ScopedTimeLogger
3447
{
3548
public:
@@ -45,7 +58,7 @@ namespace gladius
4558
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - m_start);
4659
constexpr int64_t threshold = 1;
4760

48-
if (duration.count() > threshold)
61+
//if (duration.count() > threshold)
4962
{
5063
std::cout << m_name << " took " << duration.count() << "ms" << std::endl;
5164
}
@@ -58,6 +71,6 @@ namespace gladius
5871
#define LOG_SCOPE_DURATION ScopedTimeLogger scopedTimeLogger(__FUNCTION__);
5972
#define LOG_SCOPE_DURATION_NAMED(name) ScopedTimeLogger scopedTimeLogger(name);
6073
// #define ProfileFunction LOG_SCOPE_DURATION
61-
// #define ProfileFunction ZoneScoped;
62-
#define ProfileFunction
74+
#define ProfileFunction ZoneScoped;
75+
// #define ProfileFunction
6376
}

0 commit comments

Comments
 (0)