Thin retained app and render runtime seams
This commit is contained in:
@@ -88,6 +88,7 @@ set(PP_LEGACY_APP_SOURCES
|
||||
src/legacy_canvas_mode_fill.cpp
|
||||
src/legacy_canvas_mode_pen_line.cpp
|
||||
src/legacy_canvas_mode_helpers.cpp
|
||||
src/legacy_document_image_import_services.cpp
|
||||
src/legacy_canvas_mode_helpers.h
|
||||
src/legacy_canvas_mode_mask.cpp
|
||||
src/legacy_canvas_mode_transform.cpp
|
||||
@@ -101,6 +102,7 @@ set(PP_LEGACY_APP_SOURCES
|
||||
src/legacy_preference_storage.h
|
||||
src/legacy_document_canvas_services.cpp
|
||||
src/legacy_document_canvas_services.h
|
||||
src/legacy_document_image_import_services.h
|
||||
src/legacy_document_layer_services.cpp
|
||||
src/legacy_document_layer_services.h
|
||||
src/legacy_history_services.cpp
|
||||
|
||||
@@ -18,6 +18,24 @@ agent or engineer to remove them without reconstructing context from chat.
|
||||
|
||||
## Reductions
|
||||
|
||||
- 2026-06-17: `DEBT-0036` was narrowed again. Retained `Shape`,
|
||||
`src/shader.cpp`, and `src/font.cpp` now queue render-thread create/update/
|
||||
destroy work through `src/renderer_gl/render_runtime_dispatch.h` instead of
|
||||
calling `App::I` directly, and `Shader` render-thread entry points now assert
|
||||
that explicit runtime contract while shader-program and mesh ownership remain
|
||||
retained.
|
||||
- 2026-06-17: `DEBT-0036` was narrowed again. `NodeStrokePreview` no longer
|
||||
owns static worker-thread, queue, or render-mutex state directly;
|
||||
`src/legacy_node_stroke_preview_runtime_services.*` now owns the retained
|
||||
preview worker lifecycle and queue helpers, leaving the node as a thinner
|
||||
adapter while the retained preview runtime still reaches app/render helpers
|
||||
internally.
|
||||
- 2026-06-17: `DEBT-0029` was narrowed again.
|
||||
`LegacyFileMenuServices::pick_image_for_import()` in
|
||||
`src/legacy_app_shell_services.cpp` now delegates retained import execution
|
||||
to `src/legacy_document_image_import_services.*`, so the File-menu adapter no
|
||||
longer defines the live `DocumentImageImportServices` implementation inline;
|
||||
legacy `Image` loading and retained canvas/import-mode execution still remain.
|
||||
- 2026-06-17: `DEBT-0003` was narrowed again. `src/app_runtime.cpp` and
|
||||
`src/app_runtime.h` now synchronize render/UI worker running state, reject
|
||||
cross-thread work once those workers stop, and drain queued work through
|
||||
|
||||
@@ -53,8 +53,9 @@ Key facts:
|
||||
- `Canvas::I` still appears hundreds of times in retained canvas modes, panels,
|
||||
and workflow bridges.
|
||||
- Raw `Node*` and callback captures remain a dominant UI lifetime risk.
|
||||
- `RTT`, `Texture2D`, `Shape`, `Shader`, `Font`, and `CanvasLayer` still route
|
||||
render work through `App::I` queues.
|
||||
- `CanvasLayer` and retained stroke-preview/runtime draw paths still depend on
|
||||
legacy render/runtime helpers, but `RTT`, `Texture2D`, `Shape`, `Shader`,
|
||||
and `TextMesh` no longer call `App::I` directly for queueing.
|
||||
- `AppRuntime` now owns synchronized running flags plus explicit post/reject,
|
||||
same-thread execution, and queue-drain behavior, but broader singleton reach
|
||||
and app-shell ownership remain.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "font.h"
|
||||
#include "legacy_gl_mesh_dispatch.h"
|
||||
#include "legacy_ui_gl_dispatch.h"
|
||||
#include "renderer_gl/render_runtime_dispatch.h"
|
||||
#include "shader.h"
|
||||
#include "asset.h"
|
||||
#include "util.h"
|
||||
@@ -202,7 +203,7 @@ std::vector<TextMesh::Token> TextMesh::tokenize(const std::string& s, const Font
|
||||
|
||||
bool TextMesh::create()
|
||||
{
|
||||
App::I->render_task([this]
|
||||
pp::renderer::gl::render_runtime_dispatch().render_task([this]
|
||||
{
|
||||
const auto mesh = pp::legacy::gl_mesh::create_mesh_objects(
|
||||
pp::renderer::gl::OpenGlMeshUpload {
|
||||
@@ -305,7 +306,7 @@ void TextMesh::update(const std::string& text, const std::string& font, int size
|
||||
cur_box -= glm::vec4(xy(f.bounds), 0, 0);
|
||||
bb = bbmax - bbmin;
|
||||
font_array_count = (int)idx.size();
|
||||
App::I->render_task([&]
|
||||
pp::renderer::gl::render_runtime_dispatch().render_task([&]
|
||||
{
|
||||
(void)pp::legacy::gl_mesh::upload_buffer_data(
|
||||
pp::renderer::gl::OpenGlBufferUpload {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "app_core/document_import.h"
|
||||
#include "legacy_app_dialog_services.h"
|
||||
#include "legacy_canvas_view_services.h"
|
||||
#include "legacy_document_image_import_services.h"
|
||||
#include "legacy_document_canvas_services.h"
|
||||
#include "legacy_history_services.h"
|
||||
#include "legacy_ui_overlay_services.h"
|
||||
@@ -51,50 +52,23 @@ public:
|
||||
|
||||
void pick_image_for_import() override
|
||||
{
|
||||
auto* app_ptr = &app_;
|
||||
app_.pick_image([app_ptr](std::string path) {
|
||||
app_.pick_image([this](std::string path) {
|
||||
Image img;
|
||||
img.load_file(path);
|
||||
const auto import_plan = pp::app::plan_document_image_import(img.width, img.height);
|
||||
if (!import_plan)
|
||||
return;
|
||||
|
||||
class LegacyDocumentImageImportServices final : public pp::app::DocumentImageImportServices {
|
||||
public:
|
||||
LegacyDocumentImageImportServices(App& app, Image& image) noexcept
|
||||
: app_(app)
|
||||
, image_(image)
|
||||
{
|
||||
}
|
||||
|
||||
void import_equirectangular(std::string_view import_path) override
|
||||
{
|
||||
if (Canvas::I)
|
||||
Canvas::I->import_equirectangular(std::string(import_path));
|
||||
}
|
||||
|
||||
void enter_transform_import(std::string_view) override
|
||||
{
|
||||
if (!app_.canvas || !app_.canvas->m_canvas)
|
||||
return;
|
||||
|
||||
auto* mode = static_cast<CanvasModeTransform*>(
|
||||
app_.canvas->m_canvas->modes[(int)kCanvasMode::Import][0]);
|
||||
mode->m_action = CanvasModeTransform::ActionType::Import;
|
||||
mode->m_source_image = std::move(image_);
|
||||
Canvas::set_mode(kCanvasMode::Import);
|
||||
}
|
||||
|
||||
private:
|
||||
App& app_;
|
||||
Image& image_;
|
||||
};
|
||||
|
||||
LegacyDocumentImageImportServices services(*app_ptr, img);
|
||||
const auto status = pp::app::execute_document_image_import_plan(
|
||||
auto* canvas = app_.canvas ? app_.canvas->m_canvas.get() : nullptr;
|
||||
auto* import_mode = canvas
|
||||
? static_cast<CanvasModeTransform*>(canvas->modes[(int)kCanvasMode::Import][0])
|
||||
: nullptr;
|
||||
const auto status = execute_legacy_document_image_import_plan(
|
||||
import_plan.value(),
|
||||
path,
|
||||
services);
|
||||
canvas,
|
||||
import_mode,
|
||||
std::move(img));
|
||||
if (!status.ok())
|
||||
LOG("Image import failed: %s", status.message);
|
||||
});
|
||||
|
||||
57
src/legacy_document_image_import_services.cpp
Normal file
57
src/legacy_document_image_import_services.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "legacy_document_image_import_services.h"
|
||||
|
||||
#include "canvas.h"
|
||||
#include "canvas_modes.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace pp::panopainter {
|
||||
namespace {
|
||||
|
||||
class LegacyDocumentImageImportServices final : public pp::app::DocumentImageImportServices {
|
||||
public:
|
||||
LegacyDocumentImageImportServices(Canvas* canvas, CanvasModeTransform* import_mode, Image image) noexcept
|
||||
: canvas_(canvas)
|
||||
, import_mode_(import_mode)
|
||||
, image_(std::move(image))
|
||||
{
|
||||
}
|
||||
|
||||
void import_equirectangular(std::string_view import_path) override
|
||||
{
|
||||
if (canvas_)
|
||||
canvas_->import_equirectangular(std::string(import_path));
|
||||
}
|
||||
|
||||
void enter_transform_import(std::string_view) override
|
||||
{
|
||||
if (!canvas_ || !import_mode_)
|
||||
return;
|
||||
|
||||
import_mode_->m_action = CanvasModeTransform::ActionType::Import;
|
||||
import_mode_->m_source_image = std::move(image_);
|
||||
Canvas::set_mode(kCanvasMode::Import);
|
||||
}
|
||||
|
||||
private:
|
||||
Canvas* canvas_ = nullptr;
|
||||
CanvasModeTransform* import_mode_ = nullptr;
|
||||
Image image_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
pp::foundation::Status execute_legacy_document_image_import_plan(
|
||||
const pp::app::DocumentImageImportPlan& plan,
|
||||
std::string_view path,
|
||||
Canvas* canvas,
|
||||
CanvasModeTransform* import_mode,
|
||||
Image image)
|
||||
{
|
||||
LegacyDocumentImageImportServices services(canvas, import_mode, std::move(image));
|
||||
return pp::app::execute_document_image_import_plan(plan, path, services);
|
||||
}
|
||||
|
||||
} // namespace pp::panopainter
|
||||
20
src/legacy_document_image_import_services.h
Normal file
20
src/legacy_document_image_import_services.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "app_core/document_import.h"
|
||||
#include "image.h"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
class Canvas;
|
||||
class CanvasModeTransform;
|
||||
|
||||
namespace pp::panopainter {
|
||||
|
||||
[[nodiscard]] pp::foundation::Status execute_legacy_document_image_import_plan(
|
||||
const pp::app::DocumentImageImportPlan& plan,
|
||||
std::string_view path,
|
||||
Canvas* canvas,
|
||||
CanvasModeTransform* import_mode,
|
||||
Image image);
|
||||
|
||||
} // namespace pp::panopainter
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "paint_renderer/compositor.h"
|
||||
#include "renderer_gl/opengl_capabilities.h"
|
||||
#include "util.h"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <stop_token>
|
||||
@@ -477,11 +478,141 @@ bool execute_legacy_node_stroke_preview_immediate_draw(NodeStrokePreview& previe
|
||||
|
||||
} // namespace pp::panopainter
|
||||
|
||||
std::atomic_int NodeStrokePreview::s_instances{ 0 };
|
||||
std::atomic_bool NodeStrokePreview::s_running{ false };
|
||||
std::mutex NodeStrokePreview::s_render_mutex;
|
||||
BlockingQueue<std::shared_ptr<NodeStrokePreview>> NodeStrokePreview::s_queue;
|
||||
namespace pp::panopainter {
|
||||
|
||||
class NodeStrokePreviewRuntime
|
||||
{
|
||||
public:
|
||||
std::mutex& render_mutex() noexcept
|
||||
{
|
||||
return render_mutex_;
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(lifecycle_mutex_);
|
||||
if (worker_.joinable())
|
||||
return;
|
||||
|
||||
worker_ = std::jthread([this](std::stop_token stop_token) {
|
||||
run(stop_token);
|
||||
});
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
std::jthread worker;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(lifecycle_mutex_);
|
||||
if (!worker_.joinable())
|
||||
return;
|
||||
|
||||
worker = std::move(worker_);
|
||||
}
|
||||
|
||||
worker.request_stop();
|
||||
queue_.UnlockGetters();
|
||||
if (worker.joinable())
|
||||
worker.join();
|
||||
}
|
||||
|
||||
void clear_queue()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(queue_.mutex);
|
||||
queue_.q.clear();
|
||||
}
|
||||
|
||||
void enqueue(const std::shared_ptr<NodeStrokePreview>& preview, bool draw_first)
|
||||
{
|
||||
if (!preview)
|
||||
return;
|
||||
|
||||
start();
|
||||
queue_.PostUnique(preview, draw_first);
|
||||
}
|
||||
|
||||
void remove(const std::shared_ptr<NodeStrokePreview>& preview)
|
||||
{
|
||||
if (!preview)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(queue_.mutex);
|
||||
auto it = std::find_if(queue_.q.begin(), queue_.q.end(), [&preview](const auto& queued) {
|
||||
return queued.first == preview;
|
||||
});
|
||||
if (it != queue_.q.end())
|
||||
queue_.q.erase(it);
|
||||
}
|
||||
|
||||
private:
|
||||
void run(std::stop_token stop_token)
|
||||
{
|
||||
BT_SetTerminate();
|
||||
|
||||
NodeStrokePreview::m_sampler_linear.create();
|
||||
NodeStrokePreview::m_sampler_linear_repeat.create(
|
||||
pp::renderer::gl::linear_texture_filter(),
|
||||
pp::renderer::gl::repeat_texture_wrap());
|
||||
NodeStrokePreview::m_sampler_mipmap.create();
|
||||
NodeStrokePreview::m_sampler_mipmap.set_filter(
|
||||
pp::renderer::gl::linear_mipmap_linear_texture_filter(),
|
||||
pp::renderer::gl::linear_texture_filter());
|
||||
NodeStrokePreview::m_brush_shape.create();
|
||||
|
||||
while (!stop_token.stop_requested())
|
||||
{
|
||||
auto node = queue_.Get();
|
||||
if (!node) {
|
||||
if (stop_token.stop_requested())
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> render_lock(render_mutex_);
|
||||
|
||||
// if the brush is not already loaded, load it and then destroy it
|
||||
const bool to_unload = (node->m_brush->m_tip_texture == nullptr);
|
||||
node->m_brush->preload();
|
||||
|
||||
pp::panopainter::execute_legacy_node_stroke_preview_render_task([node, to_unload] {
|
||||
gl_state gl;
|
||||
gl.save();
|
||||
|
||||
node->m_brush->load();
|
||||
node->draw_stroke_immediate();
|
||||
if (to_unload)
|
||||
node->m_brush->unload();
|
||||
|
||||
gl.restore();
|
||||
});
|
||||
|
||||
node->app_redraw();
|
||||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
NodeStrokePreview::m_rtt.destroy();
|
||||
NodeStrokePreview::m_rtt_mixer.destroy();
|
||||
NodeStrokePreview::m_tex.destroy();
|
||||
NodeStrokePreview::m_tex_dual.destroy();
|
||||
NodeStrokePreview::m_tex_background.destroy();
|
||||
NodeStrokePreview::m_brush_shape.destroy();
|
||||
}
|
||||
|
||||
std::mutex lifecycle_mutex_;
|
||||
std::mutex render_mutex_;
|
||||
BlockingQueue<std::shared_ptr<NodeStrokePreview>> queue_;
|
||||
std::jthread worker_;
|
||||
};
|
||||
|
||||
NodeStrokePreviewRuntime& legacy_node_stroke_preview_runtime()
|
||||
{
|
||||
static NodeStrokePreviewRuntime runtime;
|
||||
return runtime;
|
||||
}
|
||||
|
||||
} // namespace pp::panopainter
|
||||
|
||||
std::atomic_int NodeStrokePreview::s_instances{ 0 };
|
||||
RTT NodeStrokePreview::m_rtt;
|
||||
RTT NodeStrokePreview::m_rtt_mixer;
|
||||
Texture2D NodeStrokePreview::m_tex; // blending tmp texture
|
||||
@@ -491,22 +622,60 @@ Sampler NodeStrokePreview::m_sampler_linear;
|
||||
Sampler NodeStrokePreview::m_sampler_linear_repeat;
|
||||
Sampler NodeStrokePreview::m_sampler_mipmap;
|
||||
DynamicShape NodeStrokePreview::m_brush_shape;
|
||||
std::jthread NodeStrokePreview::s_renderer;
|
||||
|
||||
namespace pp::panopainter {
|
||||
|
||||
std::mutex& legacy_node_stroke_preview_render_mutex()
|
||||
{
|
||||
return legacy_node_stroke_preview_runtime().render_mutex();
|
||||
}
|
||||
|
||||
void execute_legacy_node_stroke_preview_render_task(std::function<void()> task)
|
||||
{
|
||||
if (!task)
|
||||
return;
|
||||
|
||||
App::I->render_task(std::move(task));
|
||||
}
|
||||
|
||||
void start_legacy_node_stroke_preview_worker()
|
||||
{
|
||||
legacy_node_stroke_preview_runtime().start();
|
||||
}
|
||||
|
||||
void stop_legacy_node_stroke_preview_worker()
|
||||
{
|
||||
legacy_node_stroke_preview_runtime().stop();
|
||||
}
|
||||
|
||||
void clear_legacy_node_stroke_preview_worker_queue()
|
||||
{
|
||||
legacy_node_stroke_preview_runtime().clear_queue();
|
||||
}
|
||||
|
||||
void enqueue_legacy_node_stroke_preview_worker(
|
||||
const std::shared_ptr<NodeStrokePreview>& preview,
|
||||
bool draw_first)
|
||||
{
|
||||
legacy_node_stroke_preview_runtime().enqueue(preview, draw_first);
|
||||
}
|
||||
|
||||
void remove_legacy_node_stroke_preview_worker(
|
||||
const std::shared_ptr<NodeStrokePreview>& preview)
|
||||
{
|
||||
legacy_node_stroke_preview_runtime().remove(preview);
|
||||
}
|
||||
|
||||
} // namespace pp::panopainter
|
||||
|
||||
void NodeStrokePreview::terminate_renderer()
|
||||
{
|
||||
if (!s_renderer.joinable())
|
||||
return;
|
||||
|
||||
s_running = false;
|
||||
s_renderer.request_stop();
|
||||
s_queue.UnlockGetters();
|
||||
s_renderer.join();
|
||||
pp::panopainter::stop_legacy_node_stroke_preview_worker();
|
||||
}
|
||||
|
||||
void NodeStrokePreview::empty_queue()
|
||||
{
|
||||
s_queue.q.clear();
|
||||
pp::panopainter::clear_legacy_node_stroke_preview_worker_queue();
|
||||
}
|
||||
|
||||
void NodeStrokePreview::restore_context()
|
||||
@@ -526,9 +695,9 @@ void NodeStrokePreview::clear_context()
|
||||
|
||||
Image NodeStrokePreview::render_to_image()
|
||||
{
|
||||
std::lock_guard<std::mutex> _lock(s_render_mutex);
|
||||
std::lock_guard<std::mutex> _lock(pp::panopainter::legacy_node_stroke_preview_render_mutex());
|
||||
|
||||
App::I->render_task([this] {
|
||||
pp::panopainter::execute_legacy_node_stroke_preview_render_task([this] {
|
||||
draw_stroke_immediate();
|
||||
});
|
||||
return m_tex_preview.get_image();
|
||||
@@ -538,63 +707,9 @@ void NodeStrokePreview::draw_stroke()
|
||||
{
|
||||
if (m_size.x == 0 || m_size.y == 0)
|
||||
return;
|
||||
std::unique_lock<std::mutex> queue_lock(s_queue.mutex);
|
||||
if (!s_renderer.joinable())
|
||||
{
|
||||
s_running = true;
|
||||
s_renderer = std::jthread([](std::stop_token stop_token) {
|
||||
BT_SetTerminate();
|
||||
|
||||
m_sampler_linear.create();
|
||||
m_sampler_linear_repeat.create(
|
||||
pp::renderer::gl::linear_texture_filter(),
|
||||
pp::renderer::gl::repeat_texture_wrap());
|
||||
m_sampler_mipmap.create();
|
||||
m_sampler_mipmap.set_filter(
|
||||
pp::renderer::gl::linear_mipmap_linear_texture_filter(),
|
||||
pp::renderer::gl::linear_texture_filter());
|
||||
m_brush_shape.create();
|
||||
while (s_running && !stop_token.stop_requested())
|
||||
{
|
||||
auto node = s_queue.Get();
|
||||
if (node)
|
||||
{
|
||||
std::lock_guard<std::mutex> _lock(s_render_mutex);
|
||||
|
||||
// if the brush is not already loaded, load it and then destroy it
|
||||
bool to_unload = (node->m_brush->m_tip_texture == nullptr);
|
||||
node->m_brush->preload();
|
||||
|
||||
App::I->render_task([node, to_unload]
|
||||
{
|
||||
gl_state gl;
|
||||
gl.save();
|
||||
|
||||
node->m_brush->load();
|
||||
node->draw_stroke_immediate();
|
||||
if (to_unload)
|
||||
node->m_brush->unload();
|
||||
|
||||
gl.restore();
|
||||
});
|
||||
|
||||
node->app_redraw();
|
||||
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(30));
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
m_rtt.destroy();
|
||||
m_rtt_mixer.destroy();
|
||||
m_tex.destroy();
|
||||
m_tex_dual.destroy();
|
||||
m_tex_background.destroy();
|
||||
m_brush_shape.destroy();
|
||||
s_running = false;
|
||||
});
|
||||
}
|
||||
queue_lock.unlock();
|
||||
s_queue.PostUnique(std::static_pointer_cast<NodeStrokePreview>(shared_from_this()), m_draw_first);
|
||||
pp::panopainter::enqueue_legacy_node_stroke_preview_worker(
|
||||
std::static_pointer_cast<NodeStrokePreview>(shared_from_this()),
|
||||
m_draw_first);
|
||||
}
|
||||
|
||||
void NodeStrokePreview::draw()
|
||||
@@ -637,7 +752,7 @@ void NodeStrokePreview::handle_on_screen(bool old_visibility, bool new_visibilit
|
||||
}
|
||||
else
|
||||
{
|
||||
s_queue.Remove(std::static_pointer_cast<NodeStrokePreview>(shared_from_this()));
|
||||
pp::panopainter::remove_legacy_node_stroke_preview_worker(std::static_pointer_cast<NodeStrokePreview>(shared_from_this()));
|
||||
m_tex_preview.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
class Node;
|
||||
@@ -136,6 +137,17 @@ struct LegacyNodeStrokePreviewImmediateDrawRequest {
|
||||
[[nodiscard]] bool execute_legacy_node_stroke_preview_immediate_runtime(
|
||||
const LegacyNodeStrokePreviewImmediateRuntimeRequest& request);
|
||||
|
||||
[[nodiscard]] std::mutex& legacy_node_stroke_preview_render_mutex();
|
||||
void execute_legacy_node_stroke_preview_render_task(std::function<void()> task);
|
||||
void start_legacy_node_stroke_preview_worker();
|
||||
void stop_legacy_node_stroke_preview_worker();
|
||||
void clear_legacy_node_stroke_preview_worker_queue();
|
||||
void enqueue_legacy_node_stroke_preview_worker(
|
||||
const std::shared_ptr<NodeStrokePreview>& preview,
|
||||
bool draw_first);
|
||||
void remove_legacy_node_stroke_preview_worker(
|
||||
const std::shared_ptr<NodeStrokePreview>& preview);
|
||||
|
||||
void initialize_legacy_node_stroke_preview_clone(Node* dest);
|
||||
[[nodiscard]] bool execute_legacy_node_stroke_preview_immediate_draw(NodeStrokePreview& preview);
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include "node_border.h"
|
||||
#include "rtt.h"
|
||||
#include "brush.h"
|
||||
@@ -9,10 +8,15 @@
|
||||
#include "legacy_node_stroke_preview_execution_services.h"
|
||||
#include "legacy_node_stroke_preview_runtime_services.h"
|
||||
|
||||
namespace pp::panopainter {
|
||||
class NodeStrokePreviewRuntime;
|
||||
}
|
||||
|
||||
class NodeStrokePreview : public NodeBorder
|
||||
{
|
||||
using StrokeFrame = pp::panopainter::LegacyNodeStrokePreviewFrame;
|
||||
|
||||
friend class pp::panopainter::NodeStrokePreviewRuntime;
|
||||
friend bool pp::panopainter::execute_legacy_node_stroke_preview_immediate_draw(NodeStrokePreview& preview);
|
||||
|
||||
static RTT m_rtt;
|
||||
@@ -28,10 +32,6 @@ class NodeStrokePreview : public NodeBorder
|
||||
public:
|
||||
using parent = NodeBorder;
|
||||
static std::atomic_int s_instances;
|
||||
static std::atomic_bool s_running;
|
||||
static std::mutex s_render_mutex;
|
||||
static std::jthread s_renderer;
|
||||
static BlockingQueue<std::shared_ptr<NodeStrokePreview>> s_queue;
|
||||
static void terminate_renderer();
|
||||
static void empty_queue();
|
||||
std::shared_ptr<Brush> m_brush;
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
#include "log.h"
|
||||
#include "shader.h"
|
||||
#include "asset.h"
|
||||
#include "app.h"
|
||||
#include "legacy_gl_shader_dispatch.h"
|
||||
#include "renderer_gl/opengl_capabilities.h"
|
||||
#include "renderer_gl/render_runtime_dispatch.h"
|
||||
#include "renderer_gl/shader_bindings.h"
|
||||
|
||||
#include <cstdint>
|
||||
@@ -165,7 +165,7 @@ bool Shader::reload()
|
||||
bool Shader::create(const std::string& vertex, const std::string& fragment)
|
||||
{
|
||||
bool ret = true;
|
||||
App::I->render_task([this, &ret, vertex, fragment]
|
||||
pp::renderer::gl::render_runtime_dispatch().render_task([this, &ret, vertex, fragment]
|
||||
{
|
||||
static char infolog[4096];
|
||||
const auto vertex_shader = pp::renderer::gl::compile_opengl_shader_source(
|
||||
@@ -337,7 +337,7 @@ void Shader::destroy()
|
||||
{
|
||||
if (prog)
|
||||
{
|
||||
App::I->render_task_async([prog=prog]
|
||||
pp::renderer::gl::render_runtime_dispatch().render_task_async([prog=prog]
|
||||
{
|
||||
const auto status = pp::renderer::gl::delete_opengl_program(
|
||||
static_cast<std::uint32_t>(prog),
|
||||
@@ -352,6 +352,7 @@ void Shader::destroy()
|
||||
|
||||
void Shader::use()
|
||||
{
|
||||
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||
const auto status = pp::renderer::gl::use_opengl_program(
|
||||
static_cast<std::uint32_t>(prog),
|
||||
pp::legacy::gl_shader::program_use_dispatch());
|
||||
@@ -360,6 +361,7 @@ void Shader::use()
|
||||
}
|
||||
void Shader::u_vec4(kShaderUniform id, const glm::vec4& v)
|
||||
{
|
||||
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||
if (m_umap.count(id) == 0)
|
||||
LOG("UNIFORM vec4 %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||
else
|
||||
@@ -374,6 +376,7 @@ void Shader::u_vec4(kShaderUniform id, const glm::vec4& v)
|
||||
}
|
||||
void Shader::u_vec3(kShaderUniform id, const glm::vec3& v)
|
||||
{
|
||||
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||
if (m_umap.count(id) == 0)
|
||||
LOG("UNIFORM vec3 %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||
else
|
||||
@@ -389,6 +392,7 @@ void Shader::u_vec3(kShaderUniform id, const glm::vec3& v)
|
||||
|
||||
void Shader::u_vec2(kShaderUniform id, const glm::vec2& v)
|
||||
{
|
||||
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||
if (m_umap.count(id) == 0)
|
||||
LOG("UNIFORM vec2 %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||
else
|
||||
@@ -404,6 +408,7 @@ void Shader::u_vec2(kShaderUniform id, const glm::vec2& v)
|
||||
|
||||
void Shader::u_mat4(kShaderUniform id, const glm::mat4& m)
|
||||
{
|
||||
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||
if (m_umap.count(id) == 0)
|
||||
LOG("UNIFORM mat4 %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||
else
|
||||
@@ -418,6 +423,7 @@ void Shader::u_mat4(kShaderUniform id, const glm::mat4& m)
|
||||
}
|
||||
void Shader::u_int(kShaderUniform id, int i)
|
||||
{
|
||||
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||
if (m_umap.count(id) == 0)
|
||||
LOG("UNIFORM int %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||
else
|
||||
@@ -432,6 +438,7 @@ void Shader::u_int(kShaderUniform id, int i)
|
||||
}
|
||||
void Shader::u_int(const char* uniform_name, int i)
|
||||
{
|
||||
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||
const auto location = pp::renderer::gl::get_opengl_attribute_location(
|
||||
static_cast<std::uint32_t>(prog),
|
||||
uniform_name,
|
||||
@@ -450,6 +457,7 @@ void Shader::u_int(const char* uniform_name, int i)
|
||||
}
|
||||
void Shader::u_float(kShaderUniform id, float f)
|
||||
{
|
||||
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||
if (m_umap.count(id) == 0)
|
||||
LOG("UNIFORM float %d NOT FOUND in shader %d", (int)id, (int)name)
|
||||
else
|
||||
@@ -464,6 +472,7 @@ void Shader::u_float(kShaderUniform id, float f)
|
||||
}
|
||||
GLint Shader::GetAttribLocation(const char* attribute_name)
|
||||
{
|
||||
assert(pp::renderer::gl::render_runtime_dispatch().is_render_thread());
|
||||
const auto location = pp::renderer::gl::get_opengl_attribute_location(
|
||||
static_cast<std::uint32_t>(prog),
|
||||
attribute_name,
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#include "log.h"
|
||||
#include "legacy_gl_mesh_dispatch.h"
|
||||
#include "shape.h"
|
||||
#include "app.h"
|
||||
#include "renderer_gl/opengl_capabilities.h"
|
||||
#include "renderer_gl/render_runtime_dispatch.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
@@ -71,7 +71,7 @@ bool Shape::create_buffers_imp(GLvoid* idx, GLvoid* vertices, int isize, int vsi
|
||||
use_idx = true;
|
||||
|
||||
bool ret = false;
|
||||
App::I->render_task([&]
|
||||
pp::renderer::gl::render_runtime_dispatch().render_task([&]
|
||||
{
|
||||
destroy();
|
||||
|
||||
@@ -101,7 +101,7 @@ bool Shape::create_buffers(GLvoid* vertices, int vsize)
|
||||
use_idx = false;
|
||||
|
||||
bool ret = false;
|
||||
App::I->render_task([&]
|
||||
pp::renderer::gl::render_runtime_dispatch().render_task([&]
|
||||
{
|
||||
destroy();
|
||||
|
||||
@@ -129,7 +129,7 @@ void Shape::draw_fill() const
|
||||
if (count[0] == 0) return;
|
||||
|
||||
const auto type = static_cast<GLenum>(pp::renderer::gl::primitive_mode_for_fill_count(count[0]));
|
||||
App::I->render_task([=]
|
||||
pp::renderer::gl::render_runtime_dispatch().render_task([=]
|
||||
{
|
||||
(void)pp::legacy::gl_mesh::draw_mesh(
|
||||
pp::renderer::gl::OpenGlMeshDraw {
|
||||
@@ -148,7 +148,7 @@ void Shape::draw_stroke() const
|
||||
if (count[0] == 0) return;
|
||||
|
||||
const auto type = static_cast<GLenum>(pp::renderer::gl::primitive_mode_for_stroke_count(count[1]));
|
||||
App::I->render_task([=]
|
||||
pp::renderer::gl::render_runtime_dispatch().render_task([=]
|
||||
{
|
||||
(void)pp::legacy::gl_mesh::draw_mesh(
|
||||
pp::renderer::gl::OpenGlMeshDraw {
|
||||
@@ -165,10 +165,13 @@ void Shape::draw_stroke() const
|
||||
|
||||
void Shape::destroy()
|
||||
{
|
||||
if (App::I) App::I->render_task_async([b1=buffers[0],b2=buffers[1],a1=arrays[0],a2=arrays[1]]
|
||||
if (buffers[0] || buffers[1] || arrays[0] || arrays[1])
|
||||
{
|
||||
pp::renderer::gl::render_runtime_dispatch().render_task_async([b1=buffers[0],b2=buffers[1],a1=arrays[0],a2=arrays[1]]
|
||||
{
|
||||
(void)pp::legacy::gl_mesh::delete_mesh_objects({ b1, b2 }, { a1, a2 }, "Shape::destroy");
|
||||
});
|
||||
}
|
||||
buffers[0] = buffers[1] = 0;
|
||||
arrays[0] = arrays[1] = 0;
|
||||
}
|
||||
@@ -451,7 +454,7 @@ void Plane::update_vertices(const glm::vec4* data, const glm::vec2* uvs, const g
|
||||
vertices[i].pos.z = q;
|
||||
}
|
||||
|
||||
App::I->render_task([this]
|
||||
pp::renderer::gl::render_runtime_dispatch().render_task([this]
|
||||
{
|
||||
(void)pp::legacy::gl_mesh::upload_buffer_data(
|
||||
pp::renderer::gl::OpenGlBufferUpload {
|
||||
@@ -732,7 +735,7 @@ void Sphere::create_impl(int rings, int sectors, float radius,
|
||||
}
|
||||
void LineSegment::update_vertices(const glm::vec4 data[2])
|
||||
{
|
||||
App::I->render_task([&]
|
||||
pp::renderer::gl::render_runtime_dispatch().render_task([&]
|
||||
{
|
||||
static vertex_t vertices[2];
|
||||
vertices[0] = { data[0], { 0, 0 } }; // A
|
||||
@@ -750,7 +753,7 @@ void LineSegment::update_vertices(const glm::vec4 data[2])
|
||||
}
|
||||
void DynamicShape::update_vertices(vertex_t* vertices, int vcount)
|
||||
{
|
||||
App::I->render_task([&]
|
||||
pp::renderer::gl::render_runtime_dispatch().render_task([&]
|
||||
{
|
||||
count[0] = vcount;
|
||||
count[1] = vcount;
|
||||
|
||||
Reference in New Issue
Block a user