-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathRenderResourceRegistry.cpp
More file actions
159 lines (128 loc) · 6.16 KB
/
Copy pathRenderResourceRegistry.cpp
File metadata and controls
159 lines (128 loc) · 6.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*****************************************************************************
* weBIGeo
* Copyright (C) 2026 Gerald Kimmersdorfer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#include "RenderResourceRegistry.h"
#include <QDebug>
#include <QFile>
#include <cassert>
#include <chrono>
namespace webgpu {
RenderResourceRegistry::RenderResourceRegistry()
{
m_preprocessor.set_file_reader([this](const std::string& name) { return read_shader_source(name); });
m_preprocessor.set_error_callback([](const std::string& message) { qFatal("%s", message.c_str()); });
}
void RenderResourceRegistry::set_local_shader_path(const std::string& target, const std::string& path) { m_local_shader_paths[target] = path; }
void RenderResourceRegistry::register_shader(const std::string& name, const std::string& source_path)
{
if (has_shader(name)) // treat re-registration as a no-op
return;
m_shader_index[name] = m_shaders.size();
m_shaders.push_back({ source_path, nullptr });
if (m_device != nullptr)
m_shaders.back().module = compile_shader(m_device, source_path);
}
bool RenderResourceRegistry::has_shader(const std::string& name) const { return m_shader_index.find(name) != m_shader_index.end(); }
const raii::ShaderModule& RenderResourceRegistry::shader(const std::string& name) const
{
auto it = m_shader_index.find(name);
assert(it != m_shader_index.end());
return *m_shaders[it->second].module;
}
void RenderResourceRegistry::register_bind_group_layout(const std::string& name, std::function<std::unique_ptr<raii::BindGroupLayout>(WGPUDevice)> factory)
{
if (has_bind_group_layout(name)) // treat re-registration as a no-op
return;
m_layout_index[name] = m_layouts.size();
m_layouts.push_back({ name, factory, nullptr });
if (m_device != nullptr)
m_layouts.back().layout = factory(m_device);
}
bool RenderResourceRegistry::has_bind_group_layout(const std::string& name) const { return m_layout_index.find(name) != m_layout_index.end(); }
const raii::BindGroupLayout& RenderResourceRegistry::bind_group_layout(const std::string& name) const
{
auto it = m_layout_index.find(name);
assert(it != m_layout_index.end());
return *m_layouts[it->second].layout;
}
void RenderResourceRegistry::register_pipeline(std::function<void(WGPUDevice, const RenderResourceRegistry&)> recreate_fn)
{
m_pipeline_fns.push_back(recreate_fn);
if (m_device != nullptr)
recreate_fn(m_device, *this);
}
void RenderResourceRegistry::recreate_all(WGPUDevice device)
{
m_device = device;
auto start = std::chrono::high_resolution_clock::now();
m_preprocessor.clear_cache();
for (auto& entry : m_shaders)
entry.module = compile_shader(device, entry.source_path);
for (auto& entry : m_layouts)
entry.layout = entry.factory(device);
for (auto& fn : m_pipeline_fns)
fn(device, *this);
auto end = std::chrono::high_resolution_clock::now();
qDebug() << "RenderResourceRegistry::recreate_all took" << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms";
}
std::string RenderResourceRegistry::read_shader_source(const std::string& source_path) const
{
// source_path is a logical shader name "target::relpath" (extension omitted).
std::string target;
std::string relpath = source_path;
if (const auto sep = source_path.find("::"); sep != std::string::npos) {
target = source_path.substr(0, sep);
relpath = source_path.substr(sep + 2);
}
const std::string file_rel = relpath + ".wgsl";
if (const auto it = m_local_shader_paths.find(target); it != m_local_shader_paths.end() && !it->second.empty()) {
const std::string local = it->second + file_rel;
QFile local_file(QString::fromStdString(local));
if (local_file.open(QIODevice::ReadOnly | QIODevice::Text))
return local_file.readAll().toStdString();
}
const std::string qrc = std::string(QRC_PREFIX) + target + "/" + file_rel;
QFile file(QString::fromStdString(qrc));
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
qFatal("Could not open shader file %s", qrc.c_str());
return file.readAll().toStdString();
}
std::unique_ptr<raii::ShaderModule> RenderResourceRegistry::compile_shader_from_code(WGPUDevice device, const std::string& code, const std::string& label)
{
const std::string preprocessed = m_preprocessor.preprocess_code(code);
WGPUShaderSourceWGSL wgsl_desc {};
wgsl_desc.code = WGPUStringView { .data = preprocessed.c_str(), .length = WGPU_STRLEN };
wgsl_desc.chain.next = nullptr;
wgsl_desc.chain.sType = WGPUSType_ShaderSourceWGSL;
WGPUShaderModuleDescriptor desc {};
desc.label = WGPUStringView { .data = label.c_str(), .length = WGPU_STRLEN };
desc.nextInChain = &wgsl_desc.chain;
return std::make_unique<raii::ShaderModule>(device, desc);
}
std::unique_ptr<raii::ShaderModule> RenderResourceRegistry::compile_shader(WGPUDevice device, const std::string& source_path)
{
const std::string code = m_preprocessor.preprocess_file(source_path);
WGPUShaderSourceWGSL wgsl_desc {};
wgsl_desc.code = WGPUStringView { .data = code.c_str(), .length = WGPU_STRLEN };
wgsl_desc.chain.next = nullptr;
wgsl_desc.chain.sType = WGPUSType_ShaderSourceWGSL;
WGPUShaderModuleDescriptor desc {};
desc.label = WGPUStringView { .data = source_path.c_str(), .length = WGPU_STRLEN };
desc.nextInChain = &wgsl_desc.chain;
return std::make_unique<raii::ShaderModule>(device, desc);
}
} // namespace webgpu