载入中...
搜索中...
未找到
Gpgpu.cpp
浏览该文件的文档.
1#include "gpgpu/Gpgpu.h"
4#include "gpgpu/GpuBuffer.h"
5#include "gpgpu/Sequence.h"
7
8#include "common/Exception.h"
9#include "common/Module.h"
11#include "graphics/Graphics.h"
12
13#ifdef EVENGINE_WEBGPU
15#else
18#endif
19
20#include <simplesquirrel/simplesquirrel.hpp>
21
22#include <functional>
23
24namespace eve::gpgpu {
25namespace {
26
27std::string currentGraphicsBackend() {
28 auto *gfx = eve::ModuleManager::getInstance<eve::graphics::Graphics>("Graphics");
29 if (!gfx) gfx = eve::graphics::Graphics::create();
30 if (!gfx) return {};
31 return gfx->getBackendName();
32}
33
34} // namespace
35
37
38bool Gpgpu::isAvailable() const {
39#ifdef EVENGINE_WEBGPU
40 if (currentGraphicsBackend() != "webgpu") return false;
41 return webgpuGpgpuReady();
42#else
43 if (currentGraphicsBackend() != "vulkan") return false;
44 return vulkanGpgpuReady();
45#endif
46}
47
48ComputeShader *Gpgpu::newShader(const std::string &source) {
49#ifdef EVENGINE_WEBGPU
50 if (currentGraphicsBackend() != "webgpu")
51 throw Exception("Gpgpu.newShader: requires webgpu Graphics backend");
52 // Source is WGSL on the WebGPU backend (browsers cannot compile GLSL).
53 return webgpuNewShaderFromWgsl(source);
54#else
55 if (currentGraphicsBackend() != "vulkan")
56 throw Exception("Gpgpu.newShader: requires vulkan Graphics backend");
58#endif
59}
60
62#ifdef EVENGINE_WEBGPU
63 if (currentGraphicsBackend() != "webgpu")
64 throw Exception("Gpgpu.newShaderFromBytecode: requires webgpu Graphics backend");
65 // Load WGSL text from the given path.
66 auto *fs = eve::filesystem::Filesystem::create();
67 if (!fs) throw Exception("Gpgpu.newShaderFromBytecode: no filesystem");
68 std::unique_ptr<eve::filesystem::FileData> file(fs->read(path));
69 if (!file) throw Exception("Gpgpu.newShaderFromBytecode: cannot open '%s'", path.c_str());
70 std::string src(reinterpret_cast<const char *>(file->getData()), file->getSize());
71 return webgpuNewShaderFromWgsl(src);
72#else
73 if (currentGraphicsBackend() != "vulkan")
74 throw Exception("Gpgpu.newShaderFromBytecode: requires vulkan Graphics backend");
76#endif
77}
78
79ComputeShader *Gpgpu::newShaderFromSpvFile(const std::string &path) {
80#ifdef EVENGINE_WEBGPU
81 if (currentGraphicsBackend() != "webgpu")
82 throw Exception("Gpgpu.newShaderFromSpvFile: requires webgpu Graphics backend");
83 throw Exception("Gpgpu.newShaderFromSpvFile: SPIR-V is only supported on vulkan; "
84 "use newShaderFromBytecode with a .wgsl file on the WebGPU backend");
85#else
86 if (currentGraphicsBackend() != "vulkan")
87 throw Exception("Gpgpu.newShaderFromSpvFile: SPIR-V is only supported on vulkan");
88 return newShaderFromBytecode(path);
89#endif
90}
91
92GpuBuffer *Gpgpu::newBuffer(int byteSize, const std::string &usage) {
93#ifdef EVENGINE_WEBGPU
94 if (currentGraphicsBackend() != "webgpu")
95 throw Exception("Gpgpu.newBuffer: requires webgpu Graphics backend");
96 return webgpuNewBuffer(byteSize, usage);
97#else
98 if (currentGraphicsBackend() != "vulkan")
99 throw Exception("Gpgpu.newBuffer: requires vulkan Graphics backend");
100 return vulkanNewBuffer(byteSize, usage);
101#endif
102}
103
105#ifdef EVENGINE_WEBGPU
106 // The class exists on every backend; it reports isAvailable()==false and
107 // throws on use when the active backend is not Vulkan.
108 return new Sequence();
109#else
110 if (currentGraphicsBackend() != "vulkan")
111 throw Exception("Gpgpu.newSequence: requires vulkan Graphics backend");
112 return new Sequence();
113#endif
114}
115
116void Gpgpu::dispatch(ComputeShader *shader, int groupsX, int groupsY, int groupsZ) {
117 if (!shader) return;
118#ifdef EVENGINE_WEBGPU
119 if (currentGraphicsBackend() != "webgpu")
120 throw Exception("Gpgpu.dispatch: requires webgpu Graphics backend");
121 webgpuDispatch(shader, groupsX, groupsY, groupsZ);
122#else
123 if (currentGraphicsBackend() != "vulkan")
124 throw Exception("Gpgpu.dispatch: requires vulkan Graphics backend");
125 vulkanDispatch(shader, groupsX, groupsY, groupsZ);
126#endif
127}
128
129void Gpgpu::expose(ssq::Table &table) {
130 auto cls = table.addClass(name, Gpgpu::create, false);
131 expose(cls);
132
133 auto shader = table.addClass<ComputeShader>(
134 "ComputeShader",
135 std::function<ComputeShader *()>([]() -> ComputeShader * { return nullptr; }), true);
136 shader.addFunc("bindBuffer", &ComputeShader::bindBuffer);
137 shader.addFunc("getBoundBuffer", &ComputeShader::getBoundBuffer);
138 shader.addFunc("setFloat", &ComputeShader::setFloat);
139 shader.addFunc("getFloat", &ComputeShader::getFloat);
140 shader.addFunc("clearBindings", &ComputeShader::clearBindings);
141
142 auto buf = table.addClass<GpuBuffer>(
143 "GpuBuffer", std::function<GpuBuffer *()>([]() -> GpuBuffer * { return nullptr; }), true);
144 buf.addFunc("getSize", &GpuBuffer::getSize);
145 buf.addFunc("getUsage", &GpuBuffer::getUsage);
146 buf.addFunc("writeData", &GpuBuffer::writeData);
147 buf.addFunc("readData", &GpuBuffer::readData);
148 buf.addFunc("writeFloat32", &GpuBuffer::writeFloat32);
149 buf.addFunc("readFloat32", &GpuBuffer::readFloat32);
150 buf.addFunc("fillFloat32", &GpuBuffer::fillFloat32);
151
152 auto seq = table.addClass<Sequence>(
153 "GpuSequence",
154 std::function<Sequence *()>([]() -> Sequence * { return new Sequence(); }), true);
155 seq.addFunc("isAvailable", &Sequence::isAvailable);
156 seq.addFunc("begin", &Sequence::begin);
157 seq.addFunc("recordUpload", &Sequence::recordUpload);
158 seq.addFunc("recordDownload", &Sequence::recordDownload);
159 seq.addFunc("recordDispatch", &Sequence::recordDispatch);
160 seq.addFunc("submit", &Sequence::submit);
161
162 // Native ECS↔GPU helper (used by eve.ShaderSystem script class).
163 auto ecsSys = table.addClass<ShaderSystem>(
164 "EcsShaderSystem",
165 std::function<ShaderSystem *()>([]() -> ShaderSystem * { return new ShaderSystem(); }),
166 true);
167 ecsSys.addFunc("setGpgpu", &ShaderSystem::setGpgpu);
168 ecsSys.addFunc("getGpgpu", &ShaderSystem::getGpgpu);
169 ecsSys.addFunc("setShaderSource", &ShaderSystem::setShaderSource);
170 ecsSys.addFunc("setShader", std::function<void(ShaderSystem *, ComputeShader *)>(
171 [](ShaderSystem *self, ComputeShader *s) {
172 if (self) self->setShader(s, false);
173 }));
174 ecsSys.addFunc("getShader", &ShaderSystem::getShader);
175 ecsSys.addFunc("setLocalSize", &ShaderSystem::setLocalSize);
176 ecsSys.addFunc("getLocalSize", &ShaderSystem::getLocalSize);
177 ecsSys.addFunc("ensureBuffer", &ShaderSystem::ensureBuffer);
178 ecsSys.addFunc("getBuffer", &ShaderSystem::getBuffer);
179 ecsSys.addFunc("setFloat", &ShaderSystem::setFloat);
180 ecsSys.addFunc("getFloat", &ShaderSystem::getFloat);
181 ecsSys.addFunc("dispatch", std::function<void(ShaderSystem *, int, float)>(
182 [](ShaderSystem *self, int n, float dt) {
183 if (self) self->dispatch(n, dt);
184 }));
185 ecsSys.addFunc("clearBuffers", &ShaderSystem::clearBuffers);
186
187 table.addFunc("packEcsFloats", packScriptEntityFloats);
188 table.addFunc("unpackEcsFloats", unpackScriptEntityFloats);
189}
190
191void Gpgpu::expose(ssq::Class &cls) {
192 cls.addFunc("getName", &Gpgpu::getName);
193 cls.addFunc("isAvailable", &Gpgpu::isAvailable);
194 cls.addFunc("newShader", &Gpgpu::newShader);
195 cls.addFunc("newShaderFromBytecode", &Gpgpu::newShaderFromBytecode);
196 cls.addFunc("newShaderFromSpvFile", &Gpgpu::newShaderFromSpvFile);
197 cls.addFunc("newBuffer", &Gpgpu::newBuffer);
198 cls.addFunc("newSequence", &Gpgpu::newSequence);
199 cls.addFunc("dispatch", &Gpgpu::dispatch);
200}
201
202} // namespace eve::gpgpu
HSQOBJECT cls
Definition ECS.cpp:21
filesystem::File * file
glm::vec3 n
Definition Grass.cpp:64
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:24
Shader * shader
const char * name
Definition RockMesh.cpp:21
uint32_t s
Definition Weather.cpp:28
virtual std::string getName() const =0
Backend-agnostic compute program. Bind storage buffers then dispatch via Gpgpu::dispatch....
virtual void setFloat(int index, float value)=0
virtual GpuBuffer * getBoundBuffer(int binding) const =0
virtual void clearBindings()=0
virtual float getFloat(int index) const =0
virtual void bindBuffer(int binding, GpuBuffer *buffer)=0
Bind a storage buffer to set=0 binding. binding in [0, kMaxBindings).
GPGPU module — compute shaders + storage buffers via the active Graphics backend. Uses the graphics q...
Definition Gpgpu.h:20
ComputeShader * newShaderFromSpvFile(const std::string &path)
Vulkan SPIR-V compatibility wrapper → newShaderFromBytecode.
Definition Gpgpu.cpp:79
ComputeShader * newShader(const std::string &source)
Compile compute source for the active backend (Vulkan: GLSL via glslc).
Definition Gpgpu.cpp:48
bool isAvailable() const
True when the active Graphics backend can run compute (device initialized).
Definition Gpgpu.cpp:38
ComputeShader * newShaderFromBytecode(const std::string &path)
Load precompiled compute bytecode from Filesystem path (Vulkan: SPIR-V).
Definition Gpgpu.cpp:61
void dispatch(ComputeShader *shader, int groupsX, int groupsY=1, int groupsZ=1)
Record + submit a compute dispatch and wait for completion (sync). groups*: workgroup counts (not thr...
Definition Gpgpu.cpp:116
GpuBuffer * newBuffer(int byteSize, const std::string &usage="storage")
Allocate a GPU buffer. usage: "storage" (SSBO, device-local) | "staging" (host-visible transfer).
Definition Gpgpu.cpp:92
Sequence * newSequence()
Create a Kompute-style command Sequence: record buffer transfers and compute dispatches into one comm...
Definition Gpgpu.cpp:104
Backend-agnostic GPU buffer for compute (storage) or CPU staging transfers. Squirrel-owned; derived c...
Definition GpuBuffer.h:16
virtual void writeData(data::ByteData *data, int dstOffset=0)=0
virtual int getSize() const =0
virtual std::string getUsage() const =0
virtual void fillFloat32(float value)=0
virtual float readFloat32(int floatIndex)=0
virtual void writeFloat32(int floatIndex, float value)=0
virtual data::ByteData * readData(int srcOffset=0, int size=-1)=0
void recordUpload(GpuBuffer *dst, const void *src, uint64_t nbytes, uint64_t dstOffset=0)
Definition Sequence.cpp:66
void recordDownload(GpuBuffer *src, GpuBuffer *staging, uint64_t nbytes, uint64_t srcOffset=0)
Definition Sequence.cpp:71
void recordDispatch(ComputeShader *shader, int groupsX, int groupsY=1, int groupsZ=1)
Definition Sequence.cpp:76
bool isAvailable() const
Definition Sequence.cpp:55
Gpgpu * getGpgpu() const
GpuBuffer * getBuffer(int binding) const
GpuBuffer * ensureBuffer(int binding, int floatCount)
void setFloat(int index, float value)
float getFloat(int index) const
void setShaderSource(const std::string &glsl)
void setLocalSize(int localSize)
void setGpgpu(Gpgpu *gpu)
ComputeShader * getShader() const
ComputeShader * vulkanNewShaderFromSpirv(const std::vector< uint32_t > &spv)
从 SPIR-V 字节码创建计算着色器。
GpuBuffer * vulkanNewBuffer(int byteSize, const std::string &usage)
创建 GPU 存储/传输缓冲区;usage 为 "storage" | "vertex" 等。
int packScriptEntityFloats(ssq::Object entitiesObj, const std::string &slot, ssq::Object fieldsObj, GpuBuffer *buf)
Pack script ECS entities' component number fields into a GpuBuffer (AoS). entities: Squirrel array of...
bool vulkanGpgpuReady()
Vulkan 后端是否就绪(设备/队列可用)。
bool webgpuGpgpuReady()
void webgpuDispatch(ComputeShader *shader, int groupsX, int groupsY, int groupsZ)
int unpackScriptEntityFloats(ssq::Object entitiesObj, const std::string &slot, ssq::Object fieldsObj, GpuBuffer *buf, int entityCount)
Inverse of packScriptEntityFloats; entityCount should match pack result.
std::vector< uint32_t > loadSpirvFile(const std::string &path)
WebGpuGpuBuffer * webgpuNewBuffer(int byteSize, const std::string &usage)
std::vector< uint32_t > compileComputeGlsl(const std::string &glsl)
void vulkanDispatch(ComputeShader *shader, int groupsX, int groupsY, int groupsZ)
派发计算着色器(groupsX/Y/Z 为线程组数)。
WebGpuComputeShader * webgpuNewShaderFromWgsl(const std::string &wgsl)