Jackalope / JenExamples (public) (License: GPLv3 or later version) (since 2020-04-27) (hash sha1)
Examples for JEN framework:
- images modification and onscreen displaying;
- presudo-random noise data generation benchmark with SIMDCPP implementation comparison.

Define CMake variable JEN_PROJECT_DIR to path of JEN root project directory.
List of commits:
Subject Hash Author Date (UTC)
image example 5d6e9a53c423fca0a45dfbac79fb3ff0a85b970f Jackalope 2020-05-04 18:02:13
benchmarking example for cpu and gpu running 1,2,3,4D simplex and white noise 16153303e47565e606b8bbb7807f49f8fa150c5d TheArtOfGriefing 2020-04-26 08:08:41
glsl shaders noise library implementation: 5 hash functions, 1,2,3,4D simplex noise; 1,2,3,4D white noise d2069f88bfb3e37945f1ed64b313c977fa6dd7f7 TheArtOfGriefing 2020-04-24 01:06:25
shaders and framework test ca8a9eabcb049baeac9ba82e82c6268f05d9ec3c TheArtOfGriefing 2020-03-10 07:43:17
shaders binary d74c5bc7da8fa263b0bf8b09ff070b9f2b9f94e1 TheArtOfGriefing 2020-03-09 05:02:44
added .gitignore 6b638f2d3aee483a87554322a235d3b23aeea92e TheArtOfGriefing 2020-03-09 05:01:59
added jen framework 0a17b9c9eb165ff74e9111e7a4720f50fe6fdc67 TheArtOfGriefing 2020-03-09 05:00:19
simplex and white noise compute shaders bdaba8a192ac8e148233c3428e4ca94ac9f56b9e TheArtOfGriefing 2020-03-09 02:09:01
Commit 5d6e9a53c423fca0a45dfbac79fb3ff0a85b970f - image example
Author: Jackalope
Author date (UTC): 2020-05-04 18:02
Committer name: TheArtOfGriefing
Committer date (UTC): 2020-05-04 18:02
Parent(s): 16153303e47565e606b8bbb7807f49f8fa150c5d
Signing key:
Tree: 219a2dd2ff5bb501ff0cb1d4779bb8aa969abf56
File Lines added Lines deleted
CMakeLists.txt 14 8
libs/jen 1 1
shaders/image.comp 28 0
shaders/image.spv 0 0
shaders/noise.comp 0 0
shaders/noise.spv 0 0
src/image_main.cpp 310 0
src/noise_main.cpp 9 11
File CMakeLists.txt changed (mode: 100644) (index 9f5c0d0..280b23c)
1 1 cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
2
3 2 project("Jen Compute Examples") project("Jen Compute Examples")
4 3
5 4 add_subdirectory(libs/jen) add_subdirectory(libs/jen)
6
7 5 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY bin) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY bin)
8 add_executable(test src/main.cpp)
9 target_compile_options(test PUBLIC ${JEN_COMPILE_OPTIONS})
10 target_include_directories(test PUBLIC ${JEN_INCLUDE_DIRS})
11 target_link_libraries(test JEN)
12 6
13 configure_file(shaders/comp.spv
14 ${CMAKE_CURRENT_BINARY_DIR}/bin/shader_comp.spv COPYONLY)
7 function(add_example name)
8 add_executable(${name} src/${name}_main.cpp)
9 target_compile_options(${name} PUBLIC ${JEN_COMPILE_OPTIONS})
10 target_include_directories(${name} PUBLIC ${JEN_INCLUDE_DIRS})
11 target_link_libraries(${name} JEN)
12 endfunction()
13
14 add_example("noise")
15 add_example("image")
16
17 configure_file(shaders/noise.spv
18 ${CMAKE_CURRENT_BINARY_DIR}/bin/noise.spv COPYONLY)
19 configure_file(shaders/image.spv
20 ${CMAKE_CURRENT_BINARY_DIR}/bin/image.spv COPYONLY)
File libs/jen changed (mode: 160000) (index 7cd15af..eaffc4e)
1 Subproject commit 7cd15af2afd064302703eccd1094f4353da35c4f
1 Subproject commit eaffc4ea4768fb67f063102793ca5d781bafb0c8
File shaders/image.comp added (mode: 100644) (index 0000000..7fc211b)
1 #version 450
2 #extension GL_ARB_shader_image_load_store : require
3 #extension GL_GOOGLE_include_directive : require
4
5 #include "white_noise.glsl"
6
7 layout (local_size_x = 1, local_size_y = 1) in;
8 layout (binding = 0, rgba8ui) uniform readonly uimage2D image_src;
9 layout (binding = 1, rgba8ui) uniform uimage2D image_dst;
10
11 const uint TYPE_NONE = 0;
12 const uint TYPE_CLEAR = 1;
13 const uint TYPE_WHITE_NOISE = 2;
14
15 layout (constant_id = 0) const uint TYPE = TYPE_NONE;
16
17 uvec3 compute_pixel(ivec2 pos) {
18 switch(TYPE) {
19 case TYPE_NONE: return imageLoad(image_src, pos).rgb;
20 case TYPE_CLEAR: return uvec3(0);
21 case TYPE_WHITE_NOISE: return uvec3(255 * white_noise(0, pos));
22 }
23 }
24
25 void main() {
26 ivec2 pos = ivec2(gl_WorkGroupID.xy);
27 imageStore(image_dst, pos, uvec4(compute_pixel(pos),0));
28 }
File shaders/image.spv added (mode: 100644) (index 0000000..8fecc1c)
File shaders/noise.comp renamed from shaders/shader.comp (similarity 100%)
File shaders/noise.spv renamed from shaders/comp.spv (similarity 94%) (mode: 100644) (index 6388315..6ebb93f)
File src/image_main.cpp added (mode: 100644) (index 0000000..2bac796)
1 #include <jen/framework.h>
2 #include <mesh/cube.h>
3
4 struct ComputeBindings {
5 [[nodiscard]] jen::vk::Result
6 init(jen::vk::ModuleCompute *p_mc, math::v3u32 extent)
7 {
8 jl::array<jen::vk::ImageCreateInfo, 2> images_info;
9
10 auto &src_image = images_info[0]; {
11 src_image.extent = extent;
12 src_image.layer_count = 1;
13 src_image.mip_level_count = 1;
14 src_image.format = VK_FORMAT_R8G8B8A8_UINT;
15 src_image.type = vkw::ImType::_2D;
16 src_image.samples = 1;
17 src_image.usage = jen::vk::ImageUseFlag::TRANSFER_DST
18 | jen::vk::ImageUseFlag::STORAGE;
19 }
20 auto &dst_image = images_info[1]; {
21 dst_image = src_image;
22 dst_image.usage = jen::vk::ImageUseFlag::STORAGE
23 | jen::vk::ImageUseFlag::TRANSFER_SRC;
24 }
25
26 auto res = p_mc->create_images(images_info, images.begin());
27 if (res != VK_SUCCESS)
28 return res;
29
30 bindings[0].init(&images[0], 0);
31 bindings[1].init(&images[1], 1);
32 binds = {};
33 binds.storage_image = bindings;
34
35 this->extent = extent;
36
37 return VK_SUCCESS;
38 }
39 void destroy(jen::vk::ModuleCompute *p_mc) {
40 p_mc->destroy_images(images.begin(), images.count32());
41 }
42
43 jl::array<jen::vk::Image, 2> images;
44 jl::array<jen::vk::BindingImage, 2> bindings;
45 math::v3u32 extent;
46 jen::vk::Bindings binds;
47 };
48
49 struct Color {
50 uint8_t r,g,b,a;
51 };
52
53 enum ShaderType {
54 NONE, CLEAR, WHITE_NOISE
55 };
56
57 void
58 compute(ShaderType type, ComputeBindings *p_binds, jen::vk::ModuleCompute *p_mc,
59 Color *p_src, Color *p_dst, jl::time *p_compute_elapsed)
60 {
61 vkw::ShaderConstant type_const;
62 type_const.id = 0;
63 type_const.size = 4;
64 type_const.offset = 0;
65
66 uint32_t consts = type;
67 vkw::ShaderSpecialization spec;
68 spec.p_data = &consts;
69 spec.data_size = type_const.size;
70 spec.constants.count = 1;
71 spec.constants.p = &type_const;
72
73 jen::vk::ComputePipeline pipeline;
74
75 jen::vk::Result res;
76 res = p_mc->create_pipeline(p_binds->binds, "image.spv", &spec, &pipeline);
77 jassert_release(res == VK_SUCCESS, vkw::to_string(res));
78
79 jen::vk::BindingsSet set;
80 res = p_mc->create_bindingSet(pipeline, p_binds->binds, &set);
81
82 jen::vk::ComputeCmdUnit *p_unit;
83 res = p_mc->create_cmdUnit(&p_unit);
84 jassert_release(res == VK_SUCCESS, vkw::to_string(res));
85
86 jen::vk::ImageTransfer write;
87 write.mip_level = 0;
88 write.layer_offset = 0;
89 write.layer_count = 1;
90 write.offset = {};
91 write.extent = p_binds->extent;
92 write.p_data = p_src;
93
94 jen::vk::ImageTransfer read;
95 read = write;
96 read.p_data = p_dst;
97
98 jen::vk::ImageTransfers writes, reads;
99 writes.p_image = &p_binds->images[0];
100 writes.transfers = write;
101 reads.p_image = &p_binds->images[1];
102 reads.transfers = read;
103
104 jen::vk::ComputeInfo info = {};
105 info.p_cmdUnit = p_unit;
106 info.p_pipeline = &pipeline;
107 info.p_bindingsSet = &set;
108 info.p_bindings = &p_binds->binds;
109 info.group_count = {p_binds->extent.x, p_binds->extent.y, p_binds->extent.z};
110 info.images_writes = writes;
111 info.images_reads = reads;
112
113 auto start = jl::time::current();
114 {
115 res = p_mc->compute(info);
116 jassert_release(res == VK_SUCCESS, vkw::to_string(res));
117 res = p_mc->read(p_unit, info.buffer_reads, info.images_reads);
118 jassert_release(res == VK_SUCCESS, vkw::to_string(res));
119 }
120 *p_compute_elapsed = start.elapsed(jl::time::current());
121
122 p_mc->destroy_cmdUnit(p_unit);
123 p_mc->destroy_bindingSet(&set);
124 p_mc->destroy_pipeline(&pipeline);
125 }
126
127 struct RenderImage {
128 [[nodiscard]] jen::vk::Result
129 init_texture(jen::vk::ModuleGraphics *p_mg, math::v3u32 extent, void *p_data)
130 {
131 // data must exist until texture will be prepared in separate thread
132 // GpuTexture.state LOADING -> DONE
133 // So "static" keyword is added here, this function called only once anyway
134 static jrf::Image im;
135 im.format = jrf::Image::Format::R8G8B8A8_SRGB;
136 im.extent = {uint16_t(extent.x), uint16_t(extent.y), uint16_t(extent.z), 4};
137 im.size = vkw::format_size(VkFormat(im.format));
138 im.p_pixels = p_data;
139
140 model.tex.layer_index = 0;
141
142 return p_mg->create(&im, &model.tex.p_data, false);
143 }
144
145 [[nodiscard]] jen::vk::Result
146 init_mesh(jen::vk::ModuleGraphics *p_mg)
147 {
148 struct Vertex {
149 math::v3f pos;
150 math::v2f tex;
151 math::v3f nor;
152 };
153 static_assert (sizeof(Vertex) == sizeof(math::vector<8, float>));
154
155 using Face = mesh::cube::Face;
156 constexpr static const Vertex VERTICES[4] = {
157 {{ 0.0f, 0.0f, 1.0f }, { 0.0f, 1.0f }, mesh::cube::NORMALS[Face::TOP] },
158 {{ 1.0f, 0.0f, 1.0f }, { 1.0f, 1.0f }, mesh::cube::NORMALS[Face::TOP] },
159 {{ 1.0f, 0.0f, 0.0f }, { 1.0f, 0.0f }, mesh::cube::NORMALS[Face::TOP] },
160 {{ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f }, mesh::cube::NORMALS[Face::TOP] }
161 };
162 struct Mesh {
163 jl::array<math::v3f, 4> positions = {
164 VERTICES[0].pos, VERTICES[1].pos, VERTICES[2].pos, VERTICES[3].pos
165 };
166 jl::array<math::v2f, 4> texture_coordinate = {
167 VERTICES[0].tex, VERTICES[1].tex, VERTICES[2].tex, VERTICES[3].tex
168 };
169 jl::array<math::v3f, 4> normals = {
170 VERTICES[0].nor, VERTICES[1].nor, VERTICES[2].nor, VERTICES[3].nor
171 };
172 uint16_t indices[6] = { 0, 1, 2, 2, 3, 0 };
173 };
174
175 constexpr static const Mesh MESH = {};
176 jen::vk::WriteData write_data;
177 write_data.p = const_cast<Mesh*>(&MESH);
178 write_data.size = sizeof(MESH);
179
180
181 jen::vk::Result res = p_mg->create(write_data, &model.ver.p_data, false);
182
183 model.ver.count = 4;
184 model.ver.offsets = {};
185 model.ver.offsets[jen::vk::VAttr::POSITION] = 0;
186 model.ver.offsets[jen::vk::VAttr::TEX_COORD]
187 = offsetof(Mesh,texture_coordinate);
188 model.ver.offsets[jen::vk::VAttr::NORMAL]
189 = offsetof(Mesh,normals);
190
191 model.ind.type = vkw::IndexType::U16;
192 model.ind.count = 6;
193 model.ind.offset = offsetof(Mesh, indices);
194 model.ind.p_data = model.ver.p_data;
195
196 model.shift = {};
197 model.shader_data.position = {-0.5,1,-0.5};
198 model.shader_data.transform = math::scale<4>(1.f);
199 return res;
200 }
201
202 jen::vk::Model model;
203 };
204
205
206 struct Program
207 {
208 void run() {
209 jassert_release(jl::allocate(&p_pixels), "allocation failed");
210 for (auto &d : p_pixels->data) {
211 for (auto &c : d) {
212 c.a = 255;
213 c.r = 127;
214 c.g = 127;
215 c.b = 127;
216 }
217 }
218
219 if (not fw.init(jen::ModulesFlag::COMPUTE | jen::ModulesFlag::GRAPHICS,
220 "JEN image compute example"))
221 jabort_release("framework start failed");
222
223 fw.settings.shaders.shading =
224 jen::vk::ShaderOptions::Shading::NO_LIGHTING;
225 (void)fw.graphics.apply_settings(fw.settings);
226
227 jen::vk::Result res = binds.init(&fw.compute, EXTENT);
228 jassert_release(res == VK_SUCCESS, vkw::to_string(res));
229
230 shader_type = ShaderType::WHITE_NOISE;
231 model.model.tex.p_data = nullptr;
232 regenerate();
233 res = model.init_mesh(&fw.graphics);
234 jassert_release(res == VK_SUCCESS, vkw::to_string(res));
235
236 screen.init(fw.instance.window, {}, {0,1,0}, {0,0,1});
237 screen.frustum.zNear = 0.01f;
238 screen.frustum.zFar = 10;
239
240 bool drawn = false;
241 loop.loop(&fw, [&drawn, this](){
242 auto &w = fw.instance.window;
243 ShaderType new_st = shader_type;
244 if (w.is_on(Key::k1))
245 new_st = ShaderType::NONE;
246 if (w.is_on(Key::k2))
247 new_st = ShaderType::CLEAR;
248 if (w.is_on(Key::k3))
249 new_st = ShaderType::WHITE_NOISE;
250
251 loop.draw = w.is_damaged;
252 if (not drawn) {
253 if (model.model.tex.p_data->state == jen::vk::State::DONE
254 and
255 model.model.ver.p_data->state == jen::vk::State::DONE) {
256 drawn = true;
257 loop.draw = true;
258 }
259 }
260 if (new_st != shader_type) {
261 shader_type = new_st;
262 regenerate();
263 drawn = false;
264 }
265 if (loop.draw) {
266 screen.update(fw.instance.window);
267 fw.graphics.apply_camera(screen.camera, screen.frustum);
268 loop.models = model.model;
269 }
270 });
271
272 binds.destroy(&fw.compute);
273 fw.graphics.destroy(model.model.tex.p_data, false);
274 fw.graphics.destroy(model.model.ver.p_data, false);
275
276 fw.destroy();
277 jl::deallocate(&p_pixels);
278 }
279 void regenerate() {
280 jl::time elapsed;
281 compute(shader_type, &binds, &fw.compute,
282 reinterpret_cast<Color*>(&p_pixels->data),
283 reinterpret_cast<Color*>(&p_pixels->computed_data), &elapsed);
284
285 if (model.model.tex.p_data != nullptr)
286 fw.graphics.destroy(model.model.tex.p_data, false);
287 jen::vk::Result res;
288 res = model.init_texture(&fw.graphics, EXTENT, &p_pixels->computed_data);
289 jassert_release(res == VK_SUCCESS, vkw::to_string(res));
290 }
291
292 constexpr static const math::v3u32 EXTENT = {800,800,1};
293 struct Pixels {
294 jl::array2D<Color, EXTENT.x, EXTENT.y> data, computed_data;
295 };
296
297 ShaderType shader_type;
298 ComputeBindings binds;
299 Pixels *p_pixels;
300 jen::Framework fw;
301 screen::Static screen;
302 RenderImage model;
303 jen::Loop loop;
304 };
305
306 int main() {
307 Program program;
308 program.run();
309 return 0;
310 }
File src/noise_main.cpp renamed from src/main.cpp (similarity 96%) (mode: 100644) (index 4e23be9..6b42189)
... ... struct ComputeBindings {
159 159 auto &uniform = bindings[0]; auto &uniform = bindings[0];
160 160 auto &storage = bindings[1]; auto &storage = bindings[1];
161 161
162 binds.uniform_texel_buffer = {};
163 binds.storage_texel_buffer = {};
162 binds = {};
164 163 binds.uniform_buffer = uniform; binds.uniform_buffer = uniform;
165 164 binds.storage_buffer = storage; binds.storage_buffer = storage;
166 165 return VK_SUCCESS; return VK_SUCCESS;
 
... ... compute_test(ShaderNoiseType noise_type, u32 work_scale, i32 seed, f32 *p_dst,
194 193 consts[0] = noise_type; consts[0] = noise_type;
195 194 consts[1] = work_group_size; consts[1] = work_group_size;
196 195 vkw::ShaderSpecialization spec; vkw::ShaderSpecialization spec;
197 spec.p_data = &noise_type;
196 spec.p_data = &consts;
198 197 spec.data_size = noise_type_const.size + workgroup_size_const.size; spec.data_size = noise_type_const.size + workgroup_size_const.size;
199 spec.constants.count = 1;
198 spec.constants.count = shader_consts.count();
200 199 spec.constants.p = shader_consts.begin(); spec.constants.p = shader_consts.begin();
201 200 jen::vk::ComputePipeline pipeline; jen::vk::ComputePipeline pipeline;
202 201
203 202 jen::vk::Result res; jen::vk::Result res;
204 res = p_mc->create_pipeline(p_binds->binds, "shader_comp.spv",
205 &spec, &pipeline);
203 res = p_mc->create_pipeline(p_binds->binds, "noise.spv", &spec, &pipeline);
206 204 jassert_release(res == VK_SUCCESS, vkw::to_string(res)); jassert_release(res == VK_SUCCESS, vkw::to_string(res));
207 205
208 206 jen::vk::BindingsSet set; jen::vk::BindingsSet set;
 
... ... compute_test(ShaderNoiseType noise_type, u32 work_scale, i32 seed, f32 *p_dst,
229 227 info.p_pipeline = &pipeline; info.p_pipeline = &pipeline;
230 228 info.p_bindingsSet = &set; info.p_bindingsSet = &set;
231 229 info.group_count = {work_groups,1,1}; info.group_count = {work_groups,1,1};
232 info.writes.p = &write;
233 info.writes.count = 1;
234 info.reads.p = &read;
235 info.reads.count = 1;
230 info.buffer_writes = write;
231 info.buffer_reads = read;
232 info.images_writes = {};
233 info.images_reads = {};
236 234
237 235 auto start = jl::time::current(); auto start = jl::time::current();
238 236 { {
239 237 res = p_mc->compute(info); res = p_mc->compute(info);
240 238 jassert_release(res == VK_SUCCESS, vkw::to_string(res)); jassert_release(res == VK_SUCCESS, vkw::to_string(res));
241 res = p_mc->read(p_unit, info.reads);
239 res = p_mc->read(p_unit, info.buffer_reads, {});
242 240 jassert_release(res == VK_SUCCESS, vkw::to_string(res)); jassert_release(res == VK_SUCCESS, vkw::to_string(res));
243 241 } }
244 242 *p_compute_elapsed = start.elapsed(jl::time::current()); *p_compute_elapsed = start.elapsed(jl::time::current());
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/Jackalope/JenExamples

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/Jackalope/JenExamples

Clone this repository using git:
git clone git://git.rocketgit.com/user/Jackalope/JenExamples

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main