MethaneAsteroids
579 строк · 26.5 Кб
1/******************************************************************************
2
3Copyright 2019-2020 Evgeny Gorodetskiy
4
5Licensed under the Apache License, Version 2.0 (the "License"),
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16
17*******************************************************************************
18
19FILE: AsteroidsApp.cpp
20Sample demonstrating parallel rendering of the distinct asteroids massive
21
22******************************************************************************/
23
24#include "AsteroidsApp.h"
25#include "AsteroidsAppController.h"
26
27#include <Methane/Graphics/AppCameraController.h>
28#include <Methane/Data/TimeAnimation.h>
29#include <Methane/Data/AppIconsProvider.h>
30#include <Methane/Instrumentation.h>
31
32#include <memory>
33#include <thread>
34#include <array>
35#include <map>
36#include <magic_enum.hpp>
37
38namespace Methane::Samples
39{
40
41struct MutableParameters
42{
43uint32_t instances_count;
44uint32_t unique_mesh_count;
45uint32_t textures_count;
46float scale_ratio;
47};
48
49constexpr uint32_t g_max_complexity = 9;
50static const std::array<MutableParameters, g_max_complexity+1> g_mutable_parameters{ {
51{ 1000U, 35U, 10U, 0.6F }, // 0
52{ 2000U, 50U, 10U, 0.5F }, // 1
53{ 3000U, 75U, 20U, 0.45F }, // 2
54{ 4000U, 100U, 20U, 0.4F }, // 3
55{ 5000U, 200U, 30U, 0.33F }, // 4
56{ 10000U, 300U, 30U, 0.3F }, // 5
57{ 15000U, 400U, 40U, 0.27F }, // 6
58{ 20000U, 500U, 40U, 0.23F }, // 7
59{ 35000U, 750U, 50U, 0.2F }, // 8
60{ 50000U, 1000U, 50U, 0.17F }, // 9
61} };
62
63[[nodiscard]]
64inline uint32_t GetDefaultComplexity()
65{
66#ifdef _DEBUG
67return 1U;
68#else
69return std::thread::hardware_concurrency() / 2;
70#endif
71}
72
73[[nodiscard]]
74inline const MutableParameters& GetMutableParameters(uint32_t complexity)
75{
76return g_mutable_parameters[std::min(complexity, g_max_complexity)];
77}
78
79[[nodiscard]]
80inline const MutableParameters& GetMutableParameters()
81{
82return GetMutableParameters(GetDefaultComplexity());
83}
84
85static const std::map<pin::Keyboard::State, AsteroidsAppAction> g_asteroids_action_by_keyboard_state{
86{ { pin::Keyboard::Key::P }, AsteroidsAppAction::SwitchParallelRendering },
87{ { pin::Keyboard::Key::L }, AsteroidsAppAction::SwitchMeshLodsColoring },
88{ { pin::Keyboard::Key::Apostrophe }, AsteroidsAppAction::IncreaseMeshLodComplexity },
89{ { pin::Keyboard::Key::Semicolon }, AsteroidsAppAction::DecreaseMeshLodComplexity },
90{ { pin::Keyboard::Key::RightBracket }, AsteroidsAppAction::IncreaseComplexity },
91{ { pin::Keyboard::Key::LeftBracket }, AsteroidsAppAction::DecreaseComplexity },
92{ { pin::Keyboard::Key::Num0 }, AsteroidsAppAction::SetComplexity0 },
93{ { pin::Keyboard::Key::Num1 }, AsteroidsAppAction::SetComplexity1 },
94{ { pin::Keyboard::Key::Num2 }, AsteroidsAppAction::SetComplexity2 },
95{ { pin::Keyboard::Key::Num3 }, AsteroidsAppAction::SetComplexity3 },
96{ { pin::Keyboard::Key::Num4 }, AsteroidsAppAction::SetComplexity4 },
97{ { pin::Keyboard::Key::Num5 }, AsteroidsAppAction::SetComplexity5 },
98{ { pin::Keyboard::Key::Num6 }, AsteroidsAppAction::SetComplexity6 },
99{ { pin::Keyboard::Key::Num7 }, AsteroidsAppAction::SetComplexity7 },
100{ { pin::Keyboard::Key::Num8 }, AsteroidsAppAction::SetComplexity8 },
101{ { pin::Keyboard::Key::Num9 }, AsteroidsAppAction::SetComplexity9 },
102};
103
104void AsteroidsFrame::ReleaseScreenPassAttachmentTextures()
105{
106META_FUNCTION_TASK();
107asteroids_pass.ReleaseAttachmentTextures();
108AppFrame::ReleaseScreenPassAttachmentTextures();
109}
110
111AsteroidsApp::AsteroidsApp()
112: UserInterfaceApp(
113Graphics::CombinedAppSettings
114{ // =========================
115Platform::IApp::Settings { // platform_app:
116"Methane Asteroids", // - name
117{ 0.8, 0.8 }, // - size
118{ 640U, 480U }, // - min_size
119false, // - is_full_screen
120&Data::IconProvider::Get(), // - icon_resources_ptr
121}, // =========================
122Graphics::IApp::Settings { // graphics_app:
123rhi::RenderPassAccessMask{ // - screen_pass_access
124rhi::RenderPassAccess::ShaderResources,
125rhi::RenderPassAccess::Samplers
126},
127true, // - animations_enabled
128true, // - show_hud_in_window_title
1290 // - default_device_index
130}, // =========================
131rhi::RenderContext::Settings { // render_context:
132gfx::FrameSize(), // - frame_size
133gfx::PixelFormat::BGRA8Unorm, // - color_format
134gfx::PixelFormat::Depth32Float, // - depth_stencil_format
135std::nullopt, // - clear_color
136gfx::DepthStencilValues(0.F, {}), // - clear_depth_stencil
1373U, // - frame_buffers_count
138false, // - vsync_enabled
139false, // - is_full_screen
140{}, // - options_mask
1411000U, // - unsync_max_fps (MacOS only)
142} // =========================
143},
144UserInterface::IApp::Settings
145{
146UserInterface::HeadsUpDisplayMode::UserInterface
147},
148"Methane Asteroids sample is demonstrating parallel rendering\nof massive asteroids field dynamic simulation.")
149, m_view_camera(GetAnimations(), gfx::ActionCamera::Pivot::Aim)
150, m_light_camera(m_view_camera, GetAnimations(), gfx::ActionCamera::Pivot::Aim)
151, m_asteroids_array_settings( // Asteroids array settings:
152{ // ================
153m_view_camera, // - view_camera
154m_scene_scale, // - scale
155GetMutableParameters().instances_count, // - instance_count
156GetMutableParameters().unique_mesh_count, // - unique_mesh_count
1574U, // - subdivisions_count
158GetMutableParameters().textures_count, // - textures_count
159{ 256U, 256U }, // - texture_dimensions
1601123U, // - random_seed
16113.F, // - orbit_radius_ratio
1624.F, // - disc_radius_ratio
1630.06F, // - mesh_lod_min_screen_size
164GetMutableParameters().scale_ratio / 10.F, // - min_asteroid_scale_ratio
165GetMutableParameters().scale_ratio, // - max_asteroid_scale_ratio
166true, // - textures_array_enabled
167true // - depth_reversed
168})
169, m_asteroids_complexity(GetDefaultComplexity())
170{
171META_FUNCTION_TASK();
172
173// NOTE: Near and Far values are swapped in camera parameters (1st value is near = max depth, 2nd value is far = min depth)
174// for Reversed-Z buffer values range [ near: 1, far 0], instead of [ near 0, far 1]
175// which is used for "from near to far" drawing order for reducing pixels overdraw
176m_view_camera.ResetOrientation({ { -110.F, 75.F, 210.F }, { 0.F, -60.F, 25.F }, { 0.F, 1.F, 0.F } });
177m_view_camera.SetParameters({ 600.F /* near = max depth */, 0.01F /*far = min depth*/, 90.F /* FOV */ });
178m_view_camera.SetZoomDistanceRange({ 60.F , 400.F });
179
180m_light_camera.ResetOrientation({ { -100.F, 120.F, 0.F }, { 0.F, 0.F, 0.F }, { 0.F, 1.F, 0.F } });
181m_light_camera.SetProjection(gfx::Camera::Projection::Orthogonal);
182m_light_camera.SetParameters({ -300.F, 300.F, 90.F });
183m_light_camera.Resize(Data::FloatSize(120.F, 120.F));
184
185AddInputControllers({
186std::make_shared<AsteroidsAppController>(*this, g_asteroids_action_by_keyboard_state),
187std::make_shared<gfx::AppCameraController>(m_view_camera, "VIEW CAMERA"),
188std::make_shared<gfx::AppCameraController>(m_light_camera, "LIGHT SOURCE",
189gfx::AppCameraController::ActionByMouseButton { { pin::Mouse::Button::Right, gfx::ActionCamera::MouseAction::Rotate } },
190gfx::AppCameraController::ActionByKeyboardState { { { pin::Keyboard::Key::LeftControl, pin::Keyboard::Key::L }, gfx::ActionCamera::KeyboardAction::Reset } },
191gfx::AppCameraController::ActionByKeyboardKey { }),
192});
193
194const std::string options_group = "Asteroids Options";
195add_option_group(options_group);
196add_option("-c,--complexity",
197[this](const CLI::results_t& res)
198{
199if (uint32_t complexity = 0;
200CLI::detail::lexical_cast(res[0], complexity))
201{
202SetAsteroidsComplexity(complexity);
203return true;
204}
205return false;
206}, "simulation complexity")
207->default_val(m_asteroids_complexity)
208->expected(0, static_cast<int>(g_max_complexity))
209->group(options_group);
210add_option("-s,--subdiv-count", m_asteroids_array_settings.subdivisions_count, "mesh subdivisions count")->group(options_group);
211add_option("-t,--texture-array", m_asteroids_array_settings.textures_array_enabled, "texture array enabled")->group(options_group);
212add_option("-r,--parallel-render", m_is_parallel_rendering_enabled, "parallel rendering enabled")->group(options_group);
213
214// Setup animations
215GetAnimations().push_back(std::make_shared<Data::TimeAnimation>(std::bind(&AsteroidsApp::Animate, this, std::placeholders::_1, std::placeholders::_2)));
216
217// Enable dry updates on pause to keep asteroids in sync with projection matrix dependent on window size which may change
218GetAnimations().SetDryUpdateOnPauseEnabled(true);
219
220ShowParameters();
221}
222
223AsteroidsApp::~AsteroidsApp()
224{
225META_FUNCTION_TASK();
226// Wait for GPU rendering is completed to release resources
227WaitForRenderComplete();
228}
229
230void AsteroidsApp::Init()
231{
232META_FUNCTION_TASK();
233META_SCOPE_TIMER("AsteroidsApp::Init");
234
235// Create initial render-pass pattern for asteroids rendering
236rhi::RenderPattern::Settings asteroids_render_pattern_settings = GetScreenRenderPatternSettings();
237asteroids_render_pattern_settings.color_attachments[0].load_action = rhi::RenderPass::Attachment::LoadAction::DontCare;
238asteroids_render_pattern_settings.depth_attachment->load_action = rhi::RenderPass::Attachment::LoadAction::Clear;
239asteroids_render_pattern_settings.depth_attachment->store_action = rhi::RenderPass::Attachment::StoreAction::Store;
240asteroids_render_pattern_settings.is_final_pass = false;
241m_asteroids_render_pattern = rhi::RenderPattern(GetRenderContext(), asteroids_render_pattern_settings);
242
243// Modify settings of the final screen render-pass pattern so that color and depth attachments are reused from initial asteroids render pass
244rhi::RenderPattern::Settings& screen_render_pattern_settings = GetScreenRenderPatternSettings();
245screen_render_pattern_settings.color_attachments[0].load_action = rhi::RenderPass::Attachment::LoadAction::Load;
246screen_render_pattern_settings.depth_attachment->load_action = rhi::RenderPass::Attachment::LoadAction::Load;
247
248// Screen render pattern and screen passes for all frames are initialized here based on modified settings
249UserInterfaceApp::Init();
250
251const rhi::RenderContext& context = GetRenderContext();
252rhi::CommandQueue render_cmd_queue = context.GetRenderCommandKit().GetQueue();
253const rhi::RenderContext::Settings& context_settings = context.GetSettings();
254m_view_camera.Resize(context_settings.frame_size);
255
256// Load cube-map texture images for Sky-box
257const rhi::Texture sky_box_texture = GetImageLoader().LoadImagesToTextureCube(render_cmd_queue,
258gfx::ImageLoader::CubeFaceResources
259{
260"Galaxy/PositiveX.jpg",
261"Galaxy/NegativeX.jpg",
262"Galaxy/PositiveY.jpg",
263"Galaxy/NegativeY.jpg",
264"Galaxy/PositiveZ.jpg",
265"Galaxy/NegativeZ.jpg"
266},
267{ gfx::ImageOption::Mipmapped },
268"Sky-Box Texture"
269);
270
271// Create sky-box
272m_sky_box = gfx::SkyBox(render_cmd_queue, m_asteroids_render_pattern, sky_box_texture,
273gfx::SkyBox::Settings
274{
275m_view_camera,
276m_scene_scale * 100.F,
277{ gfx::SkyBox::Option::DepthEnabled, gfx::SkyBox::Option::DepthReversed }
278});
279
280// Create planet
281m_planet_ptr = std::make_shared<Planet>(render_cmd_queue, m_asteroids_render_pattern, GetImageLoader(),
282Planet::Settings
283{
284m_view_camera,
285m_light_camera,
286"Planet/Mars.jpg", // texture_path
287hlslpp::float3(0.F, 0.F, 0.F), // position
288m_scene_scale * 3.F, // scale
2890.1F, // spin_velocity_rps
290true, // depth_reversed
291{ gfx::ImageOption::Mipmapped, // image_options
292gfx::ImageOption::SrgbColorSpace }, //
293-1.F, // lod_bias
294}
295);
296
297// Create asteroids array
298m_asteroids_array_ptr = m_asteroids_array_state_ptr
299? std::make_unique<AsteroidsArray>(render_cmd_queue, m_asteroids_render_pattern, m_asteroids_array_settings, *m_asteroids_array_state_ptr)
300: std::make_unique<AsteroidsArray>(render_cmd_queue, m_asteroids_render_pattern, m_asteroids_array_settings);
301
302const auto constants_data_size = static_cast<Data::Size>(sizeof(hlslpp::SceneConstants));
303const auto scene_uniforms_data_size = static_cast<Data::Size>(sizeof(hlslpp::SceneUniforms));
304const Data::Size asteroid_uniforms_data_size = m_asteroids_array_ptr->GetUniformsBufferSize();
305
306// Create constants buffer for frame rendering
307m_const_buffer = context.CreateBuffer(rhi::BufferSettings::ForConstantBuffer(constants_data_size));
308m_const_buffer.SetName("Constants Buffer");
309m_const_buffer.SetData(render_cmd_queue, {
310reinterpret_cast<Data::ConstRawPtr>(&m_scene_constants),
311sizeof(m_scene_constants)
312});
313
314// ========= Per-Frame Data =========
315for(AsteroidsFrame& frame : GetFrames())
316{
317// Create asteroids render pass
318frame.asteroids_pass = rhi::RenderPass(m_asteroids_render_pattern, frame.screen_pass.GetSettings());
319
320// Create parallel command list for asteroids rendering
321frame.parallel_cmd_list = rhi::ParallelRenderCommandList(context.GetRenderCommandKit().GetQueue(), frame.asteroids_pass);
322frame.parallel_cmd_list.SetParallelCommandListsCount(std::thread::hardware_concurrency());
323frame.parallel_cmd_list.SetName(fmt::format("Parallel Rendering {}", frame.index));
324frame.parallel_cmd_list.SetValidationEnabled(false);
325
326// Create serial command list for asteroids rendering
327frame.serial_cmd_list = rhi::RenderCommandList(context.GetRenderCommandKit().GetQueue(), frame.asteroids_pass);
328frame.serial_cmd_list.SetName(fmt::format("Serial Rendering {}", frame.index));
329frame.serial_cmd_list.SetValidationEnabled(false);
330
331// Create final command list for sky-box and planet rendering
332frame.final_cmd_list = rhi::RenderCommandList(context.GetRenderCommandKit().GetQueue(), frame.screen_pass);
333frame.final_cmd_list.SetName(fmt::format("Final Rendering {}", frame.index));
334frame.final_cmd_list.SetValidationEnabled(false);
335
336// Rendering command lists sequence
337frame.execute_cmd_list_set = CreateExecuteCommandListSet(frame);
338
339// Create uniforms buffer with volatile parameters for the whole scene rendering
340frame.scene_uniforms_buffer = context.CreateBuffer(rhi::BufferSettings::ForConstantBuffer(scene_uniforms_data_size, false, true));
341frame.scene_uniforms_buffer.SetName(fmt::format("Scene Uniforms Buffer {}", frame.index));
342
343// Create uniforms buffer for Sky-Box rendering
344frame.sky_box.uniforms_buffer = context.CreateBuffer(rhi::BufferSettings::ForConstantBuffer(gfx::SkyBox::GetUniformsSize(), false, true));
345frame.sky_box.uniforms_buffer.SetName(fmt::format("Sky-box Uniforms Buffer {}", frame.index));
346
347// Create uniforms buffer for Planet rendering
348frame.planet.uniforms_buffer = context.CreateBuffer(rhi::BufferSettings::ForConstantBuffer(sizeof(hlslpp::PlanetUniforms), false, true));
349frame.planet.uniforms_buffer.SetName(fmt::format("Planet Uniforms Buffer {}", frame.index));
350
351// Create uniforms buffer for Asteroids array rendering
352frame.asteroids.uniforms_buffer = context.CreateBuffer(rhi::BufferSettings::ForConstantBuffer(asteroid_uniforms_data_size, true, true));
353frame.asteroids.uniforms_buffer.SetName(fmt::format("Asteroids Array Uniforms Buffer {}", frame.index));
354
355// Resource bindings for Sky-Box rendering
356frame.sky_box.program_bindings = m_sky_box.CreateProgramBindings(frame.sky_box.uniforms_buffer, frame.index);
357frame.sky_box.program_bindings.SetName(fmt::format("Space Sky-Box Bindings {}", frame.index));
358
359// Resource bindings for Planet rendering
360frame.planet.program_bindings = m_planet_ptr->CreateProgramBindings(m_const_buffer, frame.planet.uniforms_buffer, frame.index);
361frame.planet.program_bindings.SetName(fmt::format("Planet Bindings {}", frame.index));
362
363
364// Resource bindings for Asteroids rendering
365frame.asteroids.program_bindings_per_instance = m_asteroids_array_ptr->CreateProgramBindings(m_const_buffer,
366frame.scene_uniforms_buffer,
367frame.asteroids.uniforms_buffer,
368frame.index);
369}
370
371// Update initial resource states before asteroids drawing without applying barriers on GPU (automatic state propagation from Common state works),
372// which is required for correct automatic resource barriers to be set after asteroids drawing, on planet drawing
373m_asteroids_array_ptr->CreateBeginningResourceBarriers(&m_const_buffer).ApplyTransitions();
374
375CompleteInitialization();
376META_LOG(GetParametersString());
377}
378
379bool AsteroidsApp::Resize(const gfx::FrameSize& frame_size, bool is_minimized)
380{
381META_FUNCTION_TASK();
382
383// Resize screen color and depth textures
384if (!UserInterfaceApp::Resize(frame_size, is_minimized))
385return false;
386
387// Update frame buffer and depth textures in initial & final render passes
388for (const AsteroidsFrame& frame : GetFrames())
389{
390rhi::RenderPassSettings asteroids_pass_settings{
391{
392rhi::TextureView(frame.screen_texture.GetInterface()),
393rhi::TextureView(GetDepthTexture().GetInterface())
394},
395frame_size
396};
397frame.asteroids_pass.Update(asteroids_pass_settings);
398}
399
400m_view_camera.Resize(frame_size);
401
402return true;
403}
404
405bool AsteroidsApp::Update()
406{
407META_FUNCTION_TASK();
408META_SCOPE_TIMER("AsteroidsApp::Update");
409
410if (!UserInterfaceApp::Update())
411return false;
412
413// Update scene uniforms
414m_scene_uniforms.view_proj_matrix = hlslpp::transpose(m_view_camera.GetViewProjMatrix());
415m_scene_uniforms.eye_position = m_view_camera.GetOrientation().eye;
416m_scene_uniforms.light_position = m_light_camera.GetOrientation().eye;
417
418m_sky_box.Update();
419return true;
420}
421
422bool AsteroidsApp::Animate(double elapsed_seconds, double delta_seconds) const
423{
424META_FUNCTION_TASK();
425bool update_result = m_planet_ptr->Update(elapsed_seconds, delta_seconds);
426update_result |= m_asteroids_array_ptr->Update(elapsed_seconds, delta_seconds);
427return update_result;
428}
429
430bool AsteroidsApp::Render()
431{
432META_FUNCTION_TASK();
433META_SCOPE_TIMER("AsteroidsApp::Render");
434if (!UserInterfaceApp::Render())
435return false;
436
437// Upload uniform buffers to GPU
438const AsteroidsFrame& frame = GetCurrentFrame();
439rhi::CommandQueue render_cmd_queue = GetRenderContext().GetRenderCommandKit().GetQueue();
440frame.scene_uniforms_buffer.SetData(render_cmd_queue, m_scene_uniforms_subresource);
441
442// Asteroids rendering in parallel or in main thread
443if (m_is_parallel_rendering_enabled)
444{
445GetAsteroidsArray().DrawParallel(frame.parallel_cmd_list, frame.asteroids, GetViewState());
446frame.parallel_cmd_list.Commit();
447}
448else
449{
450GetAsteroidsArray().Draw(frame.serial_cmd_list, frame.asteroids, GetViewState());
451frame.serial_cmd_list.Commit();
452}
453
454// Draw planet and sky-box after asteroids to minimize pixel overdraw
455m_planet_ptr->Draw(frame.final_cmd_list, frame.planet, GetViewState());
456m_sky_box.Draw(frame.final_cmd_list, frame.sky_box, GetViewState());
457
458RenderOverlay(frame.final_cmd_list);
459frame.final_cmd_list.Commit();
460
461// Execute rendering commands and present frame to screen
462render_cmd_queue.Execute(frame.execute_cmd_list_set);
463GetRenderContext().Present();
464
465return true;
466}
467
468void AsteroidsApp::OnContextReleased(rhi::IContext& context)
469{
470META_FUNCTION_TASK();
471META_SCOPE_TIMERS_FLUSH();
472
473if (m_asteroids_array_ptr)
474{
475m_asteroids_array_state_ptr = m_asteroids_array_ptr->GetState();
476}
477
478m_planet_ptr.reset();
479m_asteroids_array_ptr.reset();
480m_sky_box = {};
481m_const_buffer = {};
482m_asteroids_render_pattern = {};
483
484UserInterfaceApp::OnContextReleased(context);
485}
486
487void AsteroidsApp::SetAsteroidsComplexity(uint32_t asteroids_complexity)
488{
489META_FUNCTION_TASK();
490
491asteroids_complexity = std::min(g_max_complexity, asteroids_complexity);
492if (m_asteroids_complexity == asteroids_complexity)
493return;
494
495if (GetRenderContext().IsInitialized())
496{
497WaitForRenderComplete();
498}
499
500m_asteroids_complexity = asteroids_complexity;
501
502const MutableParameters& mutable_parameters = GetMutableParameters(m_asteroids_complexity);
503m_asteroids_array_settings.instance_count = mutable_parameters.instances_count;
504m_asteroids_array_settings.unique_mesh_count = mutable_parameters.unique_mesh_count;
505m_asteroids_array_settings.textures_count = mutable_parameters.textures_count;
506m_asteroids_array_settings.min_asteroid_scale_ratio = mutable_parameters.scale_ratio / 10.F;
507m_asteroids_array_settings.max_asteroid_scale_ratio = mutable_parameters.scale_ratio;
508
509m_asteroids_array_ptr.reset();
510m_asteroids_array_state_ptr.reset();
511
512if (GetRenderContext().IsInitialized())
513{
514GetRenderContext().Reset();
515}
516
517UpdateParametersText();
518}
519
520void AsteroidsApp::SetParallelRenderingEnabled(bool is_parallel_rendering_enabled)
521{
522META_FUNCTION_TASK();
523if (m_is_parallel_rendering_enabled == is_parallel_rendering_enabled)
524return;
525
526META_SCOPE_TIMERS_FLUSH();
527m_is_parallel_rendering_enabled = is_parallel_rendering_enabled;
528for(AsteroidsFrame& frame : GetFrames())
529{
530frame.execute_cmd_list_set = CreateExecuteCommandListSet(frame);
531}
532
533UpdateParametersText();
534META_LOG(GetParametersString());
535}
536
537AsteroidsArray& AsteroidsApp::GetAsteroidsArray() const
538{
539META_FUNCTION_TASK();
540META_CHECK_ARG_NOT_NULL(m_asteroids_array_ptr);
541return *m_asteroids_array_ptr;
542}
543
544std::string AsteroidsApp::GetParametersString()
545{
546META_FUNCTION_TASK();
547
548std::stringstream ss;
549ss << "Asteroids simulation parameters:"
550<< std::endl << " - simulation complexity [0.." << g_max_complexity << "]: " << m_asteroids_complexity
551<< std::endl << " - asteroid instances count: " << m_asteroids_array_settings.instance_count
552<< std::endl << " - unique meshes count: " << m_asteroids_array_settings.unique_mesh_count
553<< std::endl << " - mesh subdivisions count: " << m_asteroids_array_settings.subdivisions_count
554<< std::endl << " - unique textures count: " << m_asteroids_array_settings.textures_count << " "
555<< std::endl << " - asteroid textures size: " << static_cast<std::string>(m_asteroids_array_settings.texture_dimensions)
556<< std::endl << " - textures array binding: " << (m_asteroids_array_settings.textures_array_enabled ? "ON" : "OFF")
557<< std::endl << " - parallel rendering: " << (m_is_parallel_rendering_enabled ? "ON" : "OFF")
558<< std::endl << " - asteroid animations: " << (!GetAnimations().IsPaused() ? "ON" : "OFF")
559<< std::endl << " - CPU h/w thread count: " << std::thread::hardware_concurrency();
560
561return ss.str();
562}
563
564rhi::CommandListSet AsteroidsApp::CreateExecuteCommandListSet(const AsteroidsFrame& frame) const
565{
566return rhi::CommandListSet({
567m_is_parallel_rendering_enabled
568? static_cast<rhi::ICommandList&>(frame.parallel_cmd_list.GetInterface())
569: static_cast<rhi::ICommandList&>(frame.serial_cmd_list.GetInterface()),
570frame.final_cmd_list.GetInterface()
571}, frame.index);
572}
573
574} // namespace Methane::Samples
575
576int main(int argc, const char* argv[])
577{
578return Methane::Samples::AsteroidsApp().Run({ argc, argv });
579}
580