diff --git a/.gitignore b/.gitignore index 088a0b204..faa883978 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ /.idea/workspace.xml /.scannerwork /.sonarqube +/*.srctrl* /out /CMakeLists.txt.user diff --git a/.idea/dictionaries/egorodet.xml b/.idea/dictionaries/egorodet.xml index f055dd850..d1b12660a 100644 --- a/.idea/dictionaries/egorodet.xml +++ b/.idea/dictionaries/egorodet.xml @@ -1,8 +1,66 @@ + barycentrics bilinear + bindings + capslock + cmrc + deinitialize + deminiaturize + descs + directxtex + dxgi + dxguid + evgeny + glslang + gorodetskiy + hlsl + ifdef + iomap + itt + ittnotify + libtool + lods + macroses + mergeable + metallib + mipmapped + mult + multisample + mvpx + nominmax + nowide + numlock + oiio + perlin + phong + printscreen + processkey + rasterizer + sampler + scrollock + shcore + skybox + spherify + spirv + stbi + std::string + subdiv subresource + subresources + swapchain + texcoord + texcoords + texel + texturing + uber + uncreatable + unorm + unsync + vsync + windowssdk + wireframe \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 000000000..b5c4b892b --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,319 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 11165e577..8894138cb 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 9578c427c..c30e89863 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -3,13 +3,16 @@ + + + + - - + diff --git a/Apps/Samples/Asteroids/Asteroid.cpp b/Apps/Samples/Asteroids/Asteroid.cpp index 65e6b0906..ccb8abbf2 100644 --- a/Apps/Samples/Asteroids/Asteroid.cpp +++ b/Apps/Samples/Asteroids/Asteroid.cpp @@ -24,17 +24,16 @@ Random generated asteroid model with mesh and texture ready for rendering #include "Asteroid.h" #include -#include +#include #include -#include namespace Methane::Samples { using AsteroidColorSchema = std::array; -static gfx::Color3f TransformSRGBToLinear(const gfx::Color3f& srgb_color) +static gfx::Color3f TransformSrgbToLinear(const gfx::Color3f& srgb_color) { ITT_FUNCTION_TASK(); @@ -46,20 +45,20 @@ static gfx::Color3f TransformSRGBToLinear(const gfx::Color3f& srgb_color) return linear_color; } -static AsteroidColorSchema TransformSRGBToLinear(const AsteroidColorSchema& srgb_color_schema) +static AsteroidColorSchema TransformSrgbToLinear(const AsteroidColorSchema& srgb_color_schema) { ITT_FUNCTION_TASK(); AsteroidColorSchema linear_color_schema = {}; for (size_t i = 0; i < srgb_color_schema.size(); ++i) { - linear_color_schema[i] = TransformSRGBToLinear(srgb_color_schema[i]); + linear_color_schema[i] = TransformSrgbToLinear(srgb_color_schema[i]); } return linear_color_schema; } Asteroid::Mesh::Mesh(uint32_t subdivisions_count, bool randomize) - : gfx::IcosahedronMesh(VertexLayoutFromArray(Vertex::layout), 0.5f, subdivisions_count, true) + : gfx::IcosahedronMesh(Mesh::VertexLayout(Vertex::layout), 0.5f, subdivisions_count, true) { ITT_FUNCTION_TASK(); @@ -100,7 +99,7 @@ void Asteroid::Mesh::Randomize(uint32_t random_seed) ComputeAverageNormals(); } -Asteroid::Asteroid(gfx::Context& context) +Asteroid::Asteroid(gfx::RenderContext& context) : BaseBuffers(context, Mesh(3, true), "Asteroid") { ITT_FUNCTION_TASK(); @@ -108,13 +107,13 @@ Asteroid::Asteroid(gfx::Context& context) SetTexture(GenerateTextureArray(context, gfx::Dimensions(256, 256), 1, true, TextureNoiseParameters())); } -gfx::Texture::Ptr Asteroid::GenerateTextureArray(gfx::Context& context, const gfx::Dimensions& dimensions, uint32_t array_size, bool mipmapped, +Ptr Asteroid::GenerateTextureArray(gfx::RenderContext& context, const gfx::Dimensions& dimensions, uint32_t array_size, bool mipmapped, const TextureNoiseParameters& noise_parameters) { ITT_FUNCTION_TASK(); const gfx::Resource::SubResources sub_resources = GenerateTextureArraySubresources(dimensions, array_size, noise_parameters); - gfx::Texture::Ptr sp_texture_array = gfx::Texture::CreateImage(context, dimensions, array_size, gfx::PixelFormat::RGBA8Unorm, mipmapped); + Ptr sp_texture_array = gfx::Texture::CreateImage(context, dimensions, array_size, gfx::PixelFormat::RGBA8Unorm, mipmapped); sp_texture_array->SetData(sub_resources); return sp_texture_array; } @@ -124,9 +123,9 @@ gfx::Resource::SubResources Asteroid::GenerateTextureArraySubresources(const gfx ITT_FUNCTION_TASK(); const gfx::PixelFormat pixel_format = gfx::PixelFormat::RGBA8Unorm; - const uint32_t pixel_size = gfx::GetPixelSize(pixel_format); - const uint32_t pixels_count = dimensions.GetPixelsCount(); - const uint32_t row_stide = pixel_size * dimensions.width; + const uint32_t pixel_size = gfx::GetPixelSize(pixel_format); + const uint32_t pixels_count = dimensions.GetPixelsCount(); + const uint32_t row_stride = pixel_size * dimensions.width; gfx::Resource::SubResources sub_resources; sub_resources.reserve(array_size); @@ -137,13 +136,11 @@ gfx::Resource::SubResources Asteroid::GenerateTextureArraySubresources(const gfx for (uint32_t array_index = 0; array_index < array_size; ++array_index) { Data::Bytes sub_resource_data(pixels_count * pixel_size, 255u); - FillPerlinNoiseToTexture(sub_resource_data, dimensions, - pixel_size, row_stide, + FillPerlinNoiseToTexture(sub_resource_data, dimensions, row_stride, noise_seed_distribution(rng), noise_parameters.persistence, noise_parameters.scale, - noise_parameters.strength, - array_index); + noise_parameters.strength); sub_resources.emplace_back(std::move(sub_resource_data), gfx::Resource::SubResource::Index{ 0, array_index }); } @@ -163,7 +160,7 @@ Asteroid::Colors Asteroid::GetAsteroidRockColors(uint32_t deep_color_index, uint { 88.f, 88.f, 88.f }, { 148.f, 108.f, 102.f }, } }; - static const AsteroidColorSchema s_linear_deep_rock_colors = TransformSRGBToLinear(s_srgb_deep_rock_colors); + static const AsteroidColorSchema s_linear_deep_rock_colors = TransformSrgbToLinear(s_srgb_deep_rock_colors); static const AsteroidColorSchema s_srgb_shallow_rock_colors = { { { 156.f, 139.f, 113.f }, @@ -173,7 +170,7 @@ Asteroid::Colors Asteroid::GetAsteroidRockColors(uint32_t deep_color_index, uint { 153.f, 146.f, 136.f }, { 189.f, 181.f, 164.f }, } }; - static const AsteroidColorSchema s_linear_shallow_rock_colors = TransformSRGBToLinear(s_srgb_shallow_rock_colors); + static const AsteroidColorSchema s_linear_shallow_rock_colors = TransformSrgbToLinear(s_srgb_shallow_rock_colors); if (deep_color_index >= s_linear_deep_rock_colors.size() || shallow_color_index >= s_linear_shallow_rock_colors.size()) throw std::invalid_argument("Deep or shallow color indices are out of boundaries for asteroids color schema."); @@ -193,7 +190,7 @@ Asteroid::Colors Asteroid::GetAsteroidIceColors(uint32_t deep_color_index, uint3 { 16.f, 66.f, 66.f }, { 48.f, 103.f, 147.f } } }; - static const AsteroidColorSchema s_linear_deep_ice_colors = TransformSRGBToLinear(s_srgb_deep_ice_colors); + static const AsteroidColorSchema s_linear_deep_ice_colors = TransformSrgbToLinear(s_srgb_deep_ice_colors); static const AsteroidColorSchema s_srgb_shallow_ice_colors = { { { 199.f, 212.f, 244.f }, @@ -203,7 +200,7 @@ Asteroid::Colors Asteroid::GetAsteroidIceColors(uint32_t deep_color_index, uint3 { 167.f, 212.f, 239.f }, { 200.f, 221.f, 252.f } } }; - static const AsteroidColorSchema s_linear_shallow_ice_colors = TransformSRGBToLinear(s_srgb_shallow_ice_colors); + static const AsteroidColorSchema s_linear_shallow_ice_colors = TransformSrgbToLinear(s_srgb_shallow_ice_colors); if (deep_color_index >= s_linear_deep_ice_colors.size() || shallow_color_index >= s_linear_shallow_ice_colors.size()) throw std::invalid_argument("Deep or shallow color indices are out of boundaries for asteroids color schema."); @@ -222,7 +219,7 @@ Asteroid::Colors Asteroid::GetAsteroidLodColors(uint32_t lod_index) { 128.f, 128.f, 0.f }, // LOD-4: yellow { 128.f, 64.f, 0.f }, // LOD-5: orange } }; - static const AsteroidColorSchema s_linear_lod_deep_colors = TransformSRGBToLinear(s_srgb_lod_deep_colors); + static const AsteroidColorSchema s_linear_lod_deep_colors = TransformSrgbToLinear(s_srgb_lod_deep_colors); static const AsteroidColorSchema s_srgb_lod_shallow_colors = { { { 0.f, 255.f, 0.f }, // LOD-0: green @@ -232,7 +229,7 @@ Asteroid::Colors Asteroid::GetAsteroidLodColors(uint32_t lod_index) { 255.f, 255.f, 0.f }, // LOD-4: yellow { 255.f, 128.f, 0.f }, // LOD-5: orange } }; - static const AsteroidColorSchema s_linear_lod_shallow_colors = TransformSRGBToLinear(s_srgb_lod_shallow_colors); + static const AsteroidColorSchema s_linear_lod_shallow_colors = TransformSrgbToLinear(s_srgb_lod_shallow_colors); if (lod_index >= s_linear_lod_deep_colors.size() || lod_index >= s_linear_lod_shallow_colors.size()) throw std::invalid_argument("LOD index is out of boundaries for asteroids color schema."); @@ -240,8 +237,8 @@ Asteroid::Colors Asteroid::GetAsteroidLodColors(uint32_t lod_index) return Asteroid::Colors{ s_linear_lod_deep_colors[lod_index], s_linear_lod_shallow_colors[lod_index] }; } -void Asteroid::FillPerlinNoiseToTexture(Data::Bytes& texture_data, const gfx::Dimensions& dimensions, uint32_t pixel_size, uint32_t row_stride, - float random_seed, float persistence, float noise_scale, float noise_strength, uint32_t array_index) +void Asteroid::FillPerlinNoiseToTexture(Data::Bytes& texture_data, const gfx::Dimensions& dimensions, uint32_t row_stride, + float random_seed, float persistence, float noise_scale, float noise_strength) { ITT_FUNCTION_TASK(); @@ -259,12 +256,7 @@ void Asteroid::FillPerlinNoiseToTexture(Data::Bytes& texture_data, const gfx::Di uint8_t* texel_data = reinterpret_cast(&row_data[col]); for (size_t channel = 0; channel < 3; ++channel) { -#if 1 - const float channel_value = 255.f; -#else - const float channel_value = array_index % 3 == channel ? 255.f : 125.f; -#endif - texel_data[channel] = static_cast(channel_value * noise_intensity); + texel_data[channel] = static_cast(255.f * noise_intensity); } } } diff --git a/Apps/Samples/Asteroids/Asteroid.h b/Apps/Samples/Asteroids/Asteroid.h index 758227962..92001d87c 100644 --- a/Apps/Samples/Asteroids/Asteroid.h +++ b/Apps/Samples/Asteroids/Asteroid.h @@ -23,9 +23,10 @@ Random generated asteroid model with mesh and texture ready for rendering. #pragma once -#include +#include #include #include +#include namespace Methane::Samples { @@ -45,7 +46,6 @@ struct SHADER_STRUCT_ALIGN AsteroidUniforms class Asteroid final : public gfx::TexturedMeshBuffers { public: - using Ptr = std::unique_ptr; using BaseBuffers = gfx::TexturedMeshBuffers; struct Vertex @@ -53,7 +53,7 @@ class Asteroid final : public gfx::TexturedMeshBuffers gfx::Mesh::Position position; gfx::Mesh::Normal normal; - static constexpr const std::array layout = { + inline static const gfx::Mesh::VertexLayout layout = { gfx::Mesh::VertexField::Position, gfx::Mesh::VertexField::Normal, }; @@ -101,9 +101,9 @@ class Asteroid final : public gfx::TexturedMeshBuffers float strength = 1.5f; }; - Asteroid(gfx::Context& context); + explicit Asteroid(gfx::RenderContext& context); - static gfx::Texture::Ptr GenerateTextureArray(gfx::Context& context, const gfx::Dimensions& dimensions, uint32_t array_size, bool mipmapped, const TextureNoiseParameters& noise_parameters); + static Ptr GenerateTextureArray(gfx::RenderContext& context, const gfx::Dimensions& dimensions, uint32_t array_size, bool mipmapped, const TextureNoiseParameters& noise_parameters); static gfx::Resource::SubResources GenerateTextureArraySubresources(const gfx::Dimensions& dimensions, uint32_t array_size, const TextureNoiseParameters& noise_parameters); static constexpr size_t color_schema_size = 6u; @@ -112,8 +112,8 @@ class Asteroid final : public gfx::TexturedMeshBuffers static Colors GetAsteroidLodColors(uint32_t lod_index); private: - static void FillPerlinNoiseToTexture(Data::Bytes& texture_data, const gfx::Dimensions& dimensions, uint32_t pixel_size, uint32_t row_stride, - float random_seed, float persistence, float noise_scale, float noise_strength, uint32_t array_index); + static void FillPerlinNoiseToTexture(Data::Bytes& texture_data, const gfx::Dimensions& dimensions, uint32_t row_stride, + float random_seed, float persistence, float noise_scale, float noise_strength); }; } // namespace Methane::Samples diff --git a/Apps/Samples/Asteroids/AsteroidsApp.cpp b/Apps/Samples/Asteroids/AsteroidsApp.cpp index 0632496c3..14a0e0588 100644 --- a/Apps/Samples/Asteroids/AsteroidsApp.cpp +++ b/Apps/Samples/Asteroids/AsteroidsApp.cpp @@ -26,62 +26,62 @@ Sample demonstrating parallel rendering of the distinct asteroids massive #include #include -#include -#include +#include #include +#include #include #include #include #include -#include #include namespace Methane::Samples { -template -using ParamValues = std::array; - -template -inline ValueT GetParamValue(const ParamValues& param_values, size_t param_index) +struct MutableParameters { - return param_values[std::min(param_index, N - 1)]; -} + uint32_t instances_count; + uint32_t unique_mesh_count; + uint32_t textures_count; + float scale_ratio; +}; -inline size_t GetComplexity() +constexpr uint32_t g_max_complexity = 9; +static const std::array g_mutable_parameters = {{ + { 1000u, 35u, 10u, 0.6f }, // 0 + { 2000u, 50u, 10u, 0.5f }, // 1 + { 3000u, 75u, 20u, 0.45f }, // 2 + { 4000u, 100u, 20u, 0.4f }, // 3 + { 5000u, 200u, 30u, 0.33f }, // 4 + { 10000u, 300u, 30u, 0.3f }, // 5 + { 15000u, 400u, 40u, 0.27f }, // 6 + { 20000u, 500u, 40u, 0.23f }, // 7 + { 35000u, 750u, 50u, 0.2f }, // 8 + { 50000u, 1000u, 50u, 0.17f }, // 9 +}}; + +inline uint32_t GetDefaultComplexity() { #ifdef _DEBUG - return 1; + return 1u; #else - const size_t hw_cores_count = std::thread::hardware_concurrency() / 2; - return hw_cores_count > 0u ? hw_cores_count - 1u : 0u; + return std::thread::hardware_concurrency() / 2; #endif } -template -inline ValueT GetParamValueByComplexity(const ParamValues& param_values_by_complexity) +inline const MutableParameters& GetMutableParameters(uint32_t complexity) { - return GetParamValue(param_values_by_complexity, GetComplexity()); + return g_mutable_parameters[std::min(complexity, g_max_complexity)]; } -constexpr uint32_t g_max_complexity = 9; -static const ParamValues g_instaces_count = { -// [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] - 1000u, 2000u, 3000u, 4000u, 5000u, 10000u, 15000u, 20000u, 35000u, 50000u, -}; -static const ParamValues g_mesh_count = { - 35u, 50u, 75u, 100u, 200u, 300u, 400u, 500u, 750u, 1000u, -}; -static const ParamValues g_textures_count = { - 10u, 10u, 20u, 20u, 30u, 30u, 40u, 40u, 50u, 50u -}; -static const ParamValues g_scale_ratio = { - 0.6f, 0.5f, 0.45f, 0.4f, 0.33f, 0.3f, 0.27f, 0.23f, 0.2f, 0.17f -}; +inline const MutableParameters& GetMutableParameters() +{ + return GetMutableParameters(GetDefaultComplexity()); +} static const std::map g_asteroids_action_by_keyboard_state = { - { { pal::Keyboard::Key::F2 }, AsteroidsAppAction::ShowParameters }, + { { pal::Keyboard::Key::F3 }, AsteroidsAppAction::ShowParameters }, { { pal::Keyboard::Key::RightBracket }, AsteroidsAppAction::IncreaseComplexity }, { { pal::Keyboard::Key::LeftBracket }, AsteroidsAppAction::DecreaseComplexity }, { { pal::Keyboard::Key::P }, AsteroidsAppAction::SwitchParallelRendering }, @@ -91,57 +91,64 @@ static const std::map g_asteroids_acti }; // Common application settings -static const std::string g_app_help_text = "Asteroids sample demonstrates parallel rendering of the asteroids field observable with interactive camera."; -static const GraphicsApp::Settings g_app_settings = // Application settings: -{ // ==================== - { // app: - "Methane Asteroids", // - name - 0.8, 0.8, // - width, height - false, // - is_full_screen - }, // - { // context: - gfx::FrameSize(), // - frame_size - gfx::PixelFormat::BGRA8Unorm, // - color_format - gfx::PixelFormat::Depth32Float, // - depth_stencil_format - { /* color clearing disabled */ }, // - clear_color - gfx::DepthStencil{ 0.f, 0u }, // - clear_depth_stencil - 3u, // - frame_buffers_count - false, // - vsync_enabled - }, // - true, // show_hud_in_window_title - true // show_logo_badge +static const std::string g_app_help_text = "Methane sample demonstrating parallel rendering of massive randomly generated asteroids field observable with arc-ball camera."; +static const GraphicsApp::AllSettings g_app_settings = // Application settings: +{ // ==================== + { // platform_app: + "Methane Asteroids", // - name + 0.8, 0.8, // - width, height + false, // - is_full_screen + }, // + { // graphics_app: + gfx::RenderPass::Access::ShaderResources | // - screen_pass_access + gfx::RenderPass::Access::Samplers, // + true, // - animations_enabled + true, // - show_hud_in_window_title + true, // - show_logo_badge + 0 // - default_device_index + }, // + { // render_context: + gfx::FrameSize(), // - frame_size + gfx::PixelFormat::BGRA8Unorm, // - color_format + gfx::PixelFormat::Depth32Float, // - depth_stencil_format + { /* color clearing disabled */ }, // - clear_color + gfx::DepthStencil{ 0.f, 0 }, // - clear_depth_stencil + 3u, // - frame_buffers_count + false, // - vsync_enabled + } }; AsteroidsApp::AsteroidsApp() - : GraphicsApp(g_app_settings, gfx::RenderPass::Access::ShaderResources | gfx::RenderPass::Access::Samplers, g_app_help_text) + : GraphicsApp(g_app_settings, g_app_help_text) , m_view_camera(m_animations, gfx::ActionCamera::Pivot::Aim) , m_light_camera(m_view_camera, m_animations, gfx::ActionCamera::Pivot::Aim) , m_scene_scale(15.f) - , m_scene_constants( // Shader constants: - { // ================ - gfx::Color4f(1.f, 1.f, 1.f, 1.f), // - light_color - 1.25f, // - light_power - 0.1f, // - light_ambient_factor - 4.f // - light_specular_factor + , m_scene_constants( // Shader constants: + { // ================ + gfx::Color4f(1.f, 1.f, 1.f, 1.f), // - light_color + 1.25f, // - light_power + 0.1f, // - light_ambient_factor + 4.f // - light_specular_factor }) - , m_asteroids_array_settings( // Asteroids array settings: - { // ================ - m_view_camera, // - view_camera - m_scene_scale, // - scale - GetParamValueByComplexity(g_instaces_count), // - instance_count - GetParamValueByComplexity(g_mesh_count), // - unique_mesh_count - 4u, // - subdivisions_count - GetParamValueByComplexity(g_textures_count), // - textures_count - { 256u, 256u }, // - texture_dimensions - 1123u, // - random_seed - 13.f, // - orbit_radius_ratio - 4.f, // - disc_radius_ratio - GetParamValueByComplexity(g_scale_ratio) / 10.f,// - min_asteroid_scale_ratio - GetParamValueByComplexity(g_scale_ratio), // - max_asteroid_scale_ratio - true, // - textures_array_enabled - true // - depth_reversed + , m_asteroids_array_settings( // Asteroids array settings: + { // ================ + m_view_camera, // - view_camera + m_scene_scale, // - scale + GetMutableParameters().instances_count, // - instance_count + GetMutableParameters().unique_mesh_count, // - unique_mesh_count + 4u, // - subdivisions_count + GetMutableParameters().textures_count, // - textures_count + { 256u, 256u }, // - texture_dimensions + 1123u, // - random_seed + 13.f, // - orbit_radius_ratio + 4.f, // - disc_radius_ratio + 0.06f, // - mesh_lod_min_screen_size + GetMutableParameters().scale_ratio / 10.f, // - min_asteroid_scale_ratio + GetMutableParameters().scale_ratio, // - max_asteroid_scale_ratio + true, // - textures_array_enabled + true // - depth_reversed }) - , m_asteroids_complexity(static_cast(GetComplexity())) + , m_asteroids_complexity(static_cast(GetDefaultComplexity())) , m_is_parallel_rendering_enabled(true) { ITT_FUNCTION_TASK(); @@ -150,15 +157,15 @@ AsteroidsApp::AsteroidsApp() // for Reversed-Z buffer values range [ near: 1, far 0], instead of [ near 0, far 1] // which is used for "from near to far" drawing order for reducing pixels overdraw m_view_camera.SetOrientation({ { -110.f, 75.f, 210.f }, { 0.f, -60.f, 25.f }, { 0.f, 1.f, 0.f } }); - m_view_camera.SetParamters({ 600.f /* near = max depth */, 0.01f /*far = min depth*/, 90.f /* FOV */ }); + m_view_camera.SetParameters({ 600.f /* near = max depth */, 0.01f /*far = min depth*/, 90.f /* FOV */ }); m_view_camera.SetZoomDistanceRange({ 60.f , 400.f }); m_light_camera.SetOrientation({ { -100.f, 120.f, 0.f }, { 0.f, 0.f, 0.f }, { 0.f, 1.f, 0.f } }); m_light_camera.SetProjection(gfx::Camera::Projection::Orthogonal); - m_light_camera.SetParamters({ -300.f, 300.f, 90.f }); + m_light_camera.SetParameters({ -300.f, 300.f, 90.f }); m_light_camera.Resize(120.f, 120.f); - m_input_state.AddControllers({ + InputState().AddControllers({ std::make_shared(*this, g_asteroids_action_by_keyboard_state), std::make_shared(m_view_camera, "VIEW CAMERA"), std::make_shared(m_light_camera, "LIGHT SOURCE", @@ -166,13 +173,32 @@ AsteroidsApp::AsteroidsApp() gfx::AppCameraController::ActionByKeyboardState { { { pal::Keyboard::Key::LeftControl, pal::Keyboard::Key::L }, gfx::ActionCamera::KeyboardAction::Reset } }, gfx::AppCameraController::ActionByKeyboardKey { }), }); + + const std::string options_group = "Asteroids Options"; + add_option_group(options_group); + add_option("-c,--complexity", + [this](CLI::results_t res) { + uint32_t complexity = 0; + if (CLI::detail::lexical_cast(res[0], complexity)) + { + SetAsteroidsComplexity(complexity); + return true; + } + return false; + }, "simulation complexity", true) + ->default_val(m_asteroids_complexity) + ->expected(0, static_cast(g_max_complexity)) + ->group(options_group); + add_option("-s,--subdiv-count", m_asteroids_array_settings.subdivisions_count, "mesh subdivisions count", true)->group(options_group); + add_option("-t,--texture-array", m_asteroids_array_settings.textures_array_enabled, "texture array enabled", true)->group(options_group); + add_option("-r,--parallel-render", m_is_parallel_rendering_enabled, "parallel rendering enabled", true)->group(options_group); } AsteroidsApp::~AsteroidsApp() { ITT_FUNCTION_TASK(); // Wait for GPU rendering is completed to release resources - m_sp_context->WaitForGpu(gfx::Context::WaitFor::RenderComplete); + m_sp_context->WaitForGpu(gfx::RenderContext::WaitFor::RenderComplete); } void AsteroidsApp::Init() @@ -183,9 +209,8 @@ void AsteroidsApp::Init() GraphicsApp::Init(); assert(m_sp_context); - gfx::Context& context = *m_sp_context; - - const gfx::Context::Settings& context_settings = context.GetSettings(); + gfx::RenderContext& context = *m_sp_context; + const gfx::RenderContext::Settings& context_settings = context.GetSettings(); m_view_camera.Resize(static_cast(context_settings.frame_size.width), static_cast(context_settings.frame_size.height)); @@ -275,15 +300,15 @@ void AsteroidsApp::Init() frame.asteroids.sp_uniforms_buffer->SetName(IndexedName("Asteroids Array Uniforms Buffer", frame.index)); // Resource bindings for Sky-Box rendering - frame.skybox.resource_bindings_per_instance.resize(1); - frame.skybox.resource_bindings_per_instance[0] = m_sp_sky_box->CreateResourceBindings(frame.skybox.sp_uniforms_buffer); + frame.skybox.program_bindings_per_instance.resize(1); + frame.skybox.program_bindings_per_instance[0] = m_sp_sky_box->CreateProgramBindings(frame.skybox.sp_uniforms_buffer); // Resource bindings for Planet rendering - frame.planet.resource_bindings_per_instance.resize(1); - frame.planet.resource_bindings_per_instance[0] = m_sp_planet->CreateResourceBindings(m_sp_const_buffer, frame.planet.sp_uniforms_buffer); + frame.planet.program_bindings_per_instance.resize(1); + frame.planet.program_bindings_per_instance[0] = m_sp_planet->CreateProgramBindings(m_sp_const_buffer, frame.planet.sp_uniforms_buffer); // Resource bindings for Asteroids rendering - frame.asteroids.resource_bindings_per_instance = m_sp_asteroids_array->CreateResourceBindings(m_sp_const_buffer, frame.sp_scene_uniforms_buffer, frame.asteroids.sp_uniforms_buffer); + frame.asteroids.program_bindings_per_instance = m_sp_asteroids_array->CreateProgramBindings(m_sp_const_buffer, frame.sp_scene_uniforms_buffer, frame.asteroids.sp_uniforms_buffer); } // Setup animations @@ -357,43 +382,32 @@ bool AsteroidsApp::Render() return false; // Wait for previous frame rendering is completed and switch to next frame - m_sp_context->WaitForGpu(gfx::Context::WaitFor::FramePresented); + m_sp_context->WaitForGpu(gfx::RenderContext::WaitFor::FramePresented); AsteroidsFrame& frame = GetCurrentFrame(); // Upload uniform buffers to GPU frame.sp_scene_uniforms_buffer->SetData({ { reinterpret_cast(&m_scene_uniforms), sizeof(SceneUniforms) } }); - assert(!!m_sp_asteroids_array); - gfx::CommandList::Refs execute_cmd_lists; - - // Asteroids rendering + // Asteroids rendering in parallel or in main thread + Refs execute_cmd_lists; if (m_is_parallel_rendering_enabled) { - assert(!!frame.sp_parallel_cmd_list); - m_sp_asteroids_array->DrawParallel(*frame.sp_parallel_cmd_list, frame.asteroids); - frame.sp_parallel_cmd_list->Commit(false); + GetAsteroidsArray().DrawParallel(*frame.sp_parallel_cmd_list, frame.asteroids); + frame.sp_parallel_cmd_list->Commit(); execute_cmd_lists.push_back(*frame.sp_parallel_cmd_list); } else { - assert(!!frame.sp_serial_cmd_list); - m_sp_asteroids_array->Draw(*frame.sp_serial_cmd_list, frame.asteroids); - frame.sp_serial_cmd_list->Commit(false); + GetAsteroidsArray().Draw(*frame.sp_serial_cmd_list, frame.asteroids); + frame.sp_serial_cmd_list->Commit(); execute_cmd_lists.push_back(*frame.sp_serial_cmd_list); } - // Planet rendering - assert(!!m_sp_planet); - assert(!!frame.sp_final_cmd_list); + // Draw planet and sky-box after asteroids to minimize pixel overdraw m_sp_planet->Draw(*frame.sp_final_cmd_list, frame.planet); - - // Sky-box rendering - assert(!!m_sp_sky_box); m_sp_sky_box->Draw(*frame.sp_final_cmd_list, frame.skybox); - RenderOverlay(*frame.sp_final_cmd_list); - - frame.sp_final_cmd_list->Commit(true); + frame.sp_final_cmd_list->Commit(); execute_cmd_lists.push_back(*frame.sp_final_cmd_list); // Execute rendering commands and present frame to screen @@ -430,30 +444,33 @@ void AsteroidsApp::SetAsteroidsComplexity(uint32_t asteroids_complexity) if (m_asteroids_complexity == asteroids_complexity) return; - m_sp_context->WaitForGpu(gfx::Context::WaitFor::RenderComplete); + if (m_sp_context) + m_sp_context->WaitForGpu(gfx::RenderContext::WaitFor::RenderComplete); m_asteroids_complexity = asteroids_complexity; - m_asteroids_array_settings.instance_count = GetParamValue(g_instaces_count, m_asteroids_complexity); - m_asteroids_array_settings.unique_mesh_count = GetParamValue(g_mesh_count, m_asteroids_complexity); - m_asteroids_array_settings.textures_count = GetParamValue(g_textures_count, m_asteroids_complexity); - m_asteroids_array_settings.min_asteroid_scale_ratio = GetParamValue(g_scale_ratio, m_asteroids_complexity) / 10.f; - m_asteroids_array_settings.max_asteroid_scale_ratio = GetParamValue(g_scale_ratio, m_asteroids_complexity); + const MutableParameters& mutable_parameters = GetMutableParameters(m_asteroids_complexity); + m_asteroids_array_settings.instance_count = mutable_parameters.instances_count; + m_asteroids_array_settings.unique_mesh_count = mutable_parameters.unique_mesh_count; + m_asteroids_array_settings.textures_count = mutable_parameters.textures_count; + m_asteroids_array_settings.min_asteroid_scale_ratio = mutable_parameters.scale_ratio / 10.f; + m_asteroids_array_settings.max_asteroid_scale_ratio = mutable_parameters.scale_ratio; m_sp_asteroids_array.reset(); m_sp_asteroids_array_state.reset(); - - assert(!!m_sp_context); - m_sp_context->Reset(); + + if (m_sp_context) + m_sp_context->Reset(); } void AsteroidsApp::SetParallelRenderingEnabled(bool is_parallel_rendering_enabled) { ITT_FUNCTION_TASK(); - FLUSH_SCOPE_TIMINGS(); + if (m_is_parallel_rendering_enabled == is_parallel_rendering_enabled) + return; + FLUSH_SCOPE_TIMINGS(); m_is_parallel_rendering_enabled = is_parallel_rendering_enabled; - pal::PrintToDebugOutput(GetParametersString()); } @@ -471,12 +488,13 @@ std::string AsteroidsApp::GetParametersString() const std::stringstream ss; ss << std::endl << "Asteroids simulation parameters:" - << std::endl << " - simulation complexity: " << m_asteroids_complexity + << std::endl << " - simulation complexity [0.." << g_max_complexity << "]: " << m_asteroids_complexity << std::endl << " - asteroid instances count: " << m_asteroids_array_settings.instance_count << std::endl << " - unique meshes count: " << m_asteroids_array_settings.unique_mesh_count << std::endl << " - mesh subdivisions count: " << m_asteroids_array_settings.subdivisions_count << std::endl << " - unique textures count: " << m_asteroids_array_settings.textures_count << " " << static_cast(m_asteroids_array_settings.texture_dimensions) + << std::endl << " - textures array binding: " << (m_asteroids_array_settings.textures_array_enabled ? "enabled" : "disabled") << std::endl << " - parallel rendering: " << (m_is_parallel_rendering_enabled ? "enabled" : "disabled") << std::endl << " - CPU hardware thread count: " << std::thread::hardware_concurrency(); @@ -487,6 +505,6 @@ std::string AsteroidsApp::GetParametersString() const int main(int argc, const char* argv[]) { - Methane::Data::ScopeTimer::InitializeLogger(); + SCOPE_TIMER_INITIALIZE(Methane::Platform::Logger); return Methane::Samples::AsteroidsApp().Run({ argc, argv }); } diff --git a/Apps/Samples/Asteroids/AsteroidsApp.h b/Apps/Samples/Asteroids/AsteroidsApp.h index f6c4b2016..4d277d4b3 100644 --- a/Apps/Samples/Asteroids/AsteroidsApp.h +++ b/Apps/Samples/Asteroids/AsteroidsApp.h @@ -36,12 +36,12 @@ namespace pal = Platform; struct AsteroidsFrame final : gfx::AppFrame { - gfx::RenderPass::Ptr sp_initial_screen_pass; - gfx::RenderPass::Ptr sp_final_screen_pass; - gfx::ParallelRenderCommandList::Ptr sp_parallel_cmd_list; - gfx::RenderCommandList::Ptr sp_serial_cmd_list; - gfx::RenderCommandList::Ptr sp_final_cmd_list; - gfx::Buffer::Ptr sp_scene_uniforms_buffer; + Ptr sp_initial_screen_pass; + Ptr sp_final_screen_pass; + Ptr sp_parallel_cmd_list; + Ptr sp_serial_cmd_list; + Ptr sp_final_cmd_list; + Ptr sp_scene_uniforms_buffer; gfx::MeshBufferBindings skybox; gfx::MeshBufferBindings planet; gfx::MeshBufferBindings asteroids; @@ -98,11 +98,11 @@ class AsteroidsApp final : public GraphicsApp bool m_is_parallel_rendering_enabled = true; SceneUniforms m_scene_uniforms = { }; - gfx::Buffer::Ptr m_sp_const_buffer; - gfx::SkyBox::Ptr m_sp_sky_box; - Planet::Ptr m_sp_planet; - AsteroidsArray::Ptr m_sp_asteroids_array; - AsteroidsArray::ContentState::Ptr m_sp_asteroids_array_state; + Ptr m_sp_const_buffer; + Ptr m_sp_sky_box; + Ptr m_sp_planet; + Ptr m_sp_asteroids_array; + Ptr m_sp_asteroids_array_state; }; } // namespace Methane::Samples diff --git a/Apps/Samples/Asteroids/AsteroidsAppController.cpp b/Apps/Samples/Asteroids/AsteroidsAppController.cpp index 57f78e288..098f9990c 100644 --- a/Apps/Samples/Asteroids/AsteroidsAppController.cpp +++ b/Apps/Samples/Asteroids/AsteroidsAppController.cpp @@ -24,7 +24,7 @@ Asteroids application controller. #include "AsteroidsAppController.h" #include "AsteroidsApp.h" -#include +#include namespace Methane::Samples diff --git a/Apps/Samples/Asteroids/AsteroidsArray.cpp b/Apps/Samples/Asteroids/AsteroidsArray.cpp index b4a324939..a74443c29 100644 --- a/Apps/Samples/Asteroids/AsteroidsArray.cpp +++ b/Apps/Samples/Asteroids/AsteroidsArray.cpp @@ -26,8 +26,7 @@ Random generated asteroids array with uber mesh and textures ready for rendering #include #include #include -#include -#include +#include #include @@ -49,7 +48,7 @@ static gfx::Point3f GetRandomDirection(std::mt19937& rng) } AsteroidsArray::UberMesh::UberMesh(uint32_t instance_count, uint32_t subdivisions_count, uint32_t random_seed) - : gfx::UberMesh(gfx::Mesh::VertexLayoutFromArray(Asteroid::Vertex::layout)) + : gfx::UberMesh(Asteroid::Vertex::layout) , m_instance_count(instance_count) , m_subdivisions_count(subdivisions_count) { @@ -206,46 +205,57 @@ AsteroidsArray::ContentState::ContentState(const Settings& settings) } } -AsteroidsArray::AsteroidsArray(gfx::Context& context, Settings settings) +AsteroidsArray::AsteroidsArray(gfx::RenderContext& context, Settings settings) : AsteroidsArray(context, settings, *std::make_shared(settings)) { ITT_FUNCTION_TASK(); } -AsteroidsArray::AsteroidsArray(gfx::Context& context, Settings settings, ContentState& state) +AsteroidsArray::AsteroidsArray(gfx::RenderContext& context, Settings settings, ContentState& state) : BaseBuffers(context, state.uber_mesh, "Asteroids Array") , m_settings(std::move(settings)) , m_sp_content_state(state.shared_from_this()) , m_mesh_subset_by_instance_index(m_settings.instance_count, 0u) - , m_min_mesh_lod_screen_size_log2(std::log2(0.04f)) + , m_min_mesh_lod_screen_size_log_2(std::log2(m_settings.mesh_lod_min_screen_size)) { ITT_FUNCTION_TASK(); SCOPE_TIMER("AsteroidsArray::AsteroidsArray"); - const gfx::Context::Settings& context_settings = context.GetSettings(); + const gfx::RenderContext::Settings& context_settings = context.GetSettings(); const size_t textures_array_size = m_settings.textures_array_enabled ? m_settings.textures_count : 1; const gfx::Shader::MacroDefinitions macro_definitions = { { "TEXTURES_COUNT", std::to_string(textures_array_size) } }; - const std::set addressable_argument_names = { "g_mesh_uniforms" }; - std::set constant_argument_names = { "g_constants", "g_texture_sampler", "g_scene_uniforms" }; - if (m_settings.textures_array_enabled) - constant_argument_names.insert("g_face_textures"); gfx::RenderState::Settings state_settings; - state_settings.sp_program = gfx::Program::Create(context, { + state_settings.sp_program = gfx::Program::Create(context, + gfx::Program::Settings { - gfx::Shader::CreateVertex(context, { Data::ShaderProvider::Get(), { "Asteroids", "AsteroidVS" }, macro_definitions }), - gfx::Shader::CreatePixel( context, { Data::ShaderProvider::Get(), { "Asteroids", "AsteroidPS" }, macro_definitions }), - }, - { { { - { "input_position", "POSITION" }, - { "input_normal", "NORMAL" }, - } } }, - constant_argument_names, - addressable_argument_names, - { context_settings.color_format }, - context_settings.depth_stencil_format - }); + gfx::Program::Shaders + { + gfx::Shader::CreateVertex(context, { Data::ShaderProvider::Get(), { "Asteroids", "AsteroidVS" }, macro_definitions }), + gfx::Shader::CreatePixel( context, { Data::ShaderProvider::Get(), { "Asteroids", "AsteroidPS" }, macro_definitions }), + }, + gfx::Program::InputBufferLayouts + { + gfx::Program::InputBufferLayout { state.uber_mesh.GetVertexLayout().GetSemantics() } + }, + gfx::Program::ArgumentDescriptions + { + { { gfx::Shader::Type::All, "g_mesh_uniforms" }, gfx::Program::Argument::Modifiers::Addressable }, + { { gfx::Shader::Type::Pixel, "g_scene_uniforms" }, gfx::Program::Argument::Modifiers::Constant }, + { { gfx::Shader::Type::Pixel, "g_constants" }, gfx::Program::Argument::Modifiers::Constant }, + { { gfx::Shader::Type::Pixel, "g_texture_sampler"}, gfx::Program::Argument::Modifiers::Constant }, + { { gfx::Shader::Type::Pixel, "g_face_textures" }, m_settings.textures_array_enabled + ? gfx::Program::Argument::Modifiers::Constant + : gfx::Program::Argument::Modifiers::None }, + }, + gfx::PixelFormats + { + context_settings.color_format + }, + context_settings.depth_stencil_format + } + ); state_settings.sp_program->SetName("Asteroid Shaders"); state_settings.viewports = { gfx::GetFrameViewport(context_settings.frame_size) }; state_settings.scissor_rects = { gfx::GetFrameScissorRect(context_settings.frame_size) }; @@ -280,25 +290,28 @@ AsteroidsArray::AsteroidsArray(gfx::Context& context, Settings settings, Content { gfx::Sampler::Address::Mode::ClampToZero } }); m_sp_texture_sampler->SetName("Asteroid Texture Sampler"); + + // Initialize default uniforms to be ready to render right aways + Update(0.0, 0.0); } -gfx::MeshBufferBindings::ResourceBindingsArray AsteroidsArray::CreateResourceBindings(const gfx::Buffer::Ptr &sp_constants_buffer, - const gfx::Buffer::Ptr &sp_scene_uniforms_buffer, - const gfx::Buffer::Ptr &sp_asteroids_uniforms_buffer) +Ptrs AsteroidsArray::CreateProgramBindings(const Ptr &sp_constants_buffer, + const Ptr &sp_scene_uniforms_buffer, + const Ptr &sp_asteroids_uniforms_buffer) { ITT_FUNCTION_TASK(); - SCOPE_TIMER("AsteroidsArray::CreateResourceBindings"); + SCOPE_TIMER("AsteroidsArray::CreateProgramBindings"); - gfx::MeshBufferBindings::ResourceBindingsArray resource_bindings_array; + Ptrs program_bindings_array; if (m_settings.instance_count == 0) - return resource_bindings_array; + return program_bindings_array; const gfx::Resource::Locations face_texture_locations = m_settings.textures_array_enabled ? gfx::Resource::CreateLocations(m_unique_textures) : gfx::Resource::Locations{ { GetInstanceTexturePtr(0) } }; - resource_bindings_array.resize(m_settings.instance_count); - resource_bindings_array[0] = gfx::Program::ResourceBindings::Create(m_sp_render_state->GetSettings().sp_program, { + program_bindings_array.resize(m_settings.instance_count); + program_bindings_array[0] = gfx::ProgramBindings::Create(m_sp_render_state->GetSettings().sp_program, { { { gfx::Shader::Type::All, "g_mesh_uniforms" }, { { sp_asteroids_uniforms_buffer, GetUniformsBufferOffset(0) } } }, { { gfx::Shader::Type::Pixel, "g_scene_uniforms" }, { { sp_scene_uniforms_buffer } } }, { { gfx::Shader::Type::Pixel, "g_constants" }, { { sp_constants_buffer } } }, @@ -309,19 +322,19 @@ gfx::MeshBufferBindings::ResourceBindingsArray AsteroidsArray::CreateResourceBin Data::ParallelFor(1u, m_settings.instance_count, [&](uint32_t asteroid_index) { const Data::Size asteroid_uniform_offset = GetUniformsBufferOffset(asteroid_index); - gfx::Program::ResourceBindings::ResourceLocationsByArgument set_resoure_location_by_argument = { + gfx::ProgramBindings::ResourceLocationsByArgument set_resource_location_by_argument = { { { gfx::Shader::Type::All, "g_mesh_uniforms" }, { { sp_asteroids_uniforms_buffer, asteroid_uniform_offset } } }, }; if (!m_settings.textures_array_enabled) { - set_resoure_location_by_argument.insert( + set_resource_location_by_argument.insert( { { gfx::Shader::Type::Pixel, "g_face_textures" }, { { GetInstanceTexturePtr(asteroid_index) } } } ); } - resource_bindings_array[asteroid_index] = gfx::Program::ResourceBindings::CreateCopy(*resource_bindings_array[0], set_resoure_location_by_argument); + program_bindings_array[asteroid_index] = gfx::ProgramBindings::CreateCopy(*program_bindings_array[0], set_resource_location_by_argument); }); - return resource_bindings_array; + return program_bindings_array; } void AsteroidsArray::Resize(const gfx::FrameSize &frame_size) @@ -363,10 +376,10 @@ bool AsteroidsArray::Update(double elapsed_seconds, double /*delta_seconds*/) const gfx::Matrix44f mvp_matrix = model_matrix * view_proj_matrix; const gfx::Vector3f asteroid_position(model_matrix(3, 0), model_matrix(3, 1), model_matrix(3, 2)); - const float distance_to_eye = (eye_position - asteroid_position).length(); - const float relative_screen_size_log2 = std::log2(asteroid_parameters.scale / std::sqrt(distance_to_eye)); + const float distance_to_eye = (eye_position - asteroid_position).length(); + const float relative_screen_size_log_2 = std::log2(asteroid_parameters.scale / std::sqrt(distance_to_eye)); - const float mesh_subdiv_float = std::roundf(relative_screen_size_log2 - m_min_mesh_lod_screen_size_log2); + const float mesh_subdiv_float = std::roundf(relative_screen_size_log_2 - m_min_mesh_lod_screen_size_log_2); const uint32_t mesh_subdivision_index = std::min(m_settings.subdivisions_count - 1, static_cast(std::max(0.0f, mesh_subdiv_float))); const uint32_t mesh_subset_index = m_sp_content_state->uber_mesh.GetSubsetIndex(asteroid_parameters.mesh_instance_index, mesh_subdivision_index); const gfx::Vector2f& mesh_subset_depth_range = m_sp_content_state->uber_mesh.GetSubsetDepthRange(mesh_subset_index); @@ -405,9 +418,9 @@ void AsteroidsArray::Draw(gfx::RenderCommandList &cmd_list, gfx::MeshBufferBindi cmd_list.Reset(m_sp_render_state, "Asteroids rendering"); - assert(buffer_bindings.resource_bindings_per_instance.size() == m_settings.instance_count); - BaseBuffers::Draw(cmd_list, buffer_bindings.resource_bindings_per_instance, - gfx::Program::ResourceBindings::ApplyBehavior::ConstantOnce); + assert(buffer_bindings.program_bindings_per_instance.size() == m_settings.instance_count); + BaseBuffers::Draw(cmd_list, buffer_bindings.program_bindings_per_instance, + gfx::ProgramBindings::ApplyBehavior::ConstantOnce); } void AsteroidsArray::DrawParallel(gfx::ParallelRenderCommandList& parallel_cmd_list, gfx::MeshBufferBindings& buffer_bindings) @@ -422,21 +435,21 @@ void AsteroidsArray::DrawParallel(gfx::ParallelRenderCommandList& parallel_cmd_l parallel_cmd_list.Reset(m_sp_render_state, "Asteroids Rendering"); - assert(buffer_bindings.resource_bindings_per_instance.size() == m_settings.instance_count); - BaseBuffers::DrawParallel(parallel_cmd_list, buffer_bindings.resource_bindings_per_instance, - gfx::Program::ResourceBindings::ApplyBehavior::ConstantOnce); + assert(buffer_bindings.program_bindings_per_instance.size() == m_settings.instance_count); + BaseBuffers::DrawParallel(parallel_cmd_list, buffer_bindings.program_bindings_per_instance, + gfx::ProgramBindings::ApplyBehavior::ConstantOnce); } float AsteroidsArray::GetMinMeshLodScreenSize() const { ITT_FUNCTION_TASK(); - return std::pow(2.f, m_min_mesh_lod_screen_size_log2); + return std::pow(2.f, m_min_mesh_lod_screen_size_log_2); } void AsteroidsArray::SetMinMeshLodScreenSize(float mesh_lod_min_screen_size) { ITT_FUNCTION_TASK(); - m_min_mesh_lod_screen_size_log2 = std::log2(mesh_lod_min_screen_size); + m_min_mesh_lod_screen_size_log_2 = std::log2(mesh_lod_min_screen_size); } uint32_t AsteroidsArray::GetSubsetByInstanceIndex(uint32_t instance_index) const diff --git a/Apps/Samples/Asteroids/AsteroidsArray.h b/Apps/Samples/Asteroids/AsteroidsArray.h index db3aa1eae..c9c395de8 100644 --- a/Apps/Samples/Asteroids/AsteroidsArray.h +++ b/Apps/Samples/Asteroids/AsteroidsArray.h @@ -25,7 +25,7 @@ Random generated asteroids array with uber-mesh and textures ready for rendering #include "Asteroid.h" -#include +#include #include #include #include @@ -40,7 +40,6 @@ namespace gfx = Graphics; class AsteroidsArray final : protected gfx::TexturedMeshBuffers { public: - using Ptr = std::unique_ptr; using BaseBuffers = gfx::TexturedMeshBuffers; struct Settings @@ -55,6 +54,7 @@ class AsteroidsArray final : protected gfx::TexturedMeshBuffers { - using Ptr = std::shared_ptr; ContentState(const Settings& settings); using MeshSubsetTextureIndices = std::vector; @@ -95,16 +94,16 @@ class AsteroidsArray final : protected gfx::TexturedMeshBuffers& GetState() const { return m_sp_content_state; } + using BaseBuffers::GetUniformsBufferSize; - gfx::MeshBufferBindings::ResourceBindingsArray CreateResourceBindings(const gfx::Buffer::Ptr& sp_constants_buffer, - const gfx::Buffer::Ptr& sp_scene_uniforms_buffer, - const gfx::Buffer::Ptr& sp_asteroids_uniforms_buffer); + Ptrs CreateProgramBindings(const Ptr& sp_constants_buffer, + const Ptr& sp_scene_uniforms_buffer, + const Ptr& sp_asteroids_uniforms_buffer); void Resize(const gfx::FrameSize& frame_size); bool Update(double elapsed_seconds, double delta_seconds); @@ -125,13 +124,13 @@ class AsteroidsArray final : protected gfx::TexturedMeshBuffers; const Settings m_settings; - ContentState::Ptr m_sp_content_state; + Ptr m_sp_content_state; Textures m_unique_textures; - gfx::Sampler::Ptr m_sp_texture_sampler; - gfx::RenderState::Ptr m_sp_render_state; + Ptr m_sp_texture_sampler; + Ptr m_sp_render_state; MeshSubsetByInstanceIndex m_mesh_subset_by_instance_index; - bool m_mesh_lod_coloring_enabled = false; - float m_min_mesh_lod_screen_size_log2; + bool m_mesh_lod_coloring_enabled = false; + float m_min_mesh_lod_screen_size_log_2; }; } // namespace Methane::Samples diff --git a/Apps/Samples/Asteroids/CMakeLists.txt b/Apps/Samples/Asteroids/CMakeLists.txt index 23e319c5d..08e0ebbb2 100644 --- a/Apps/Samples/Asteroids/CMakeLists.txt +++ b/Apps/Samples/Asteroids/CMakeLists.txt @@ -40,11 +40,11 @@ add_methane_application(${TARGET} "Methane Asteroids" "Asteroids sample demonstrates parallel rendering of the asteroids field observable with interactive camera." "${METHANE_COPYRIGHT}" - "${METHANE_VERSION}" - "${METHANE_BUILD_NUMBER}" + "${METHANE_VERSION_SHORT}" + "${METHANE_VERSION_BUILD}" ) add_methane_embedded_textures(${TARGET} "${IMAGES_DIR}" "${TEXTURES}") -add_methane_shaders(${TARGET} "${SHADERS_HLSL}") +add_methane_shaders(${TARGET} "${SHADERS_HLSL}" "6_0") set_target_properties(${TARGET} PROPERTIES diff --git a/Apps/Samples/Asteroids/Planet.cpp b/Apps/Samples/Asteroids/Planet.cpp index 25d308045..09446c07e 100644 --- a/Apps/Samples/Asteroids/Planet.cpp +++ b/Apps/Samples/Asteroids/Planet.cpp @@ -24,53 +24,56 @@ Planet rendering primitive #include "Planet.h" #include -#include +#include #include #include -#include +#include namespace Methane::Samples { -struct PlanetVertex +Planet::Planet(gfx::RenderContext& context, gfx::ImageLoader& image_loader, const Settings& settings) + : Planet(context, image_loader, settings, gfx::SphereMesh(Vertex::layout, 1.f, 32, 32)) { - gfx::Mesh::Position position; - gfx::Mesh::Normal normal; - gfx::Mesh::TexCoord texcoord; - - using FieldsArray = std::array; - static constexpr const FieldsArray layout = { - gfx::Mesh::VertexField::Position, - gfx::Mesh::VertexField::Normal, - gfx::Mesh::VertexField::TexCoord, - }; -}; - -Planet::Planet(gfx::Context& context, gfx::ImageLoader& image_loader, const Settings& settings) + ITT_FUNCTION_TASK(); +} + +Planet::Planet(gfx::RenderContext& context, gfx::ImageLoader& image_loader, const Settings& settings, gfx::BaseMesh mesh) : m_settings(settings) , m_context(context) - , m_mesh_buffers(context, gfx::SphereMesh(gfx::Mesh::VertexLayoutFromArray(PlanetVertex::layout), 1.f, 32, 32), "Planet") + , m_mesh_buffers(context, mesh, "Planet") { ITT_FUNCTION_TASK(); - const gfx::Context::Settings& context_settings = context.GetSettings(); + const gfx::RenderContext::Settings& context_settings = context.GetSettings(); gfx::RenderState::Settings state_settings; - state_settings.sp_program = gfx::Program::Create(context, { + state_settings.sp_program = gfx::Program::Create(context, + gfx::Program::Settings { - gfx::Shader::CreateVertex(context, { Data::ShaderProvider::Get(), { "Planet", "PlanetVS" }, { } }), - gfx::Shader::CreatePixel( context, { Data::ShaderProvider::Get(), { "Planet", "PlanetPS" }, { } }), - }, - { { { - { "input_position", "POSITION" }, - { "input_normal", "NORMAL" }, - { "input_texcoord", "TEXCOORD" }, - } } }, - { "g_constants", "g_texture", "g_sampler" }, - { }, - { context_settings.color_format }, - context_settings.depth_stencil_format - }); + gfx::Program::Shaders + { + gfx::Shader::CreateVertex(context, { Data::ShaderProvider::Get(), { "Planet", "PlanetVS" }, { } }), + gfx::Shader::CreatePixel( context, { Data::ShaderProvider::Get(), { "Planet", "PlanetPS" }, { } }), + }, + gfx::Program::InputBufferLayouts + { + gfx::Program::InputBufferLayout { mesh.GetVertexLayout().GetSemantics() } + }, + gfx::Program::ArgumentDescriptions + { + { { gfx::Shader::Type::All, "g_uniforms" }, gfx::Program::Argument::Modifiers::None }, + { { gfx::Shader::Type::Pixel, "g_constants" }, gfx::Program::Argument::Modifiers::Constant }, + { { gfx::Shader::Type::Pixel, "g_texture" }, gfx::Program::Argument::Modifiers::Constant }, + { { gfx::Shader::Type::Pixel, "g_sampler" }, gfx::Program::Argument::Modifiers::Constant }, + }, + gfx::PixelFormats + { + context_settings.color_format + }, + context_settings.depth_stencil_format + } + ); state_settings.sp_program->SetName("Planet Shaders"); state_settings.viewports = { gfx::GetFrameViewport(context_settings.frame_size) }; state_settings.scissor_rects = { gfx::GetFrameScissorRect(context_settings.frame_size) }; @@ -88,19 +91,22 @@ Planet::Planet(gfx::Context& context, gfx::ImageLoader& image_loader, const Sett gfx::Sampler::LevelOfDetail(m_settings.lod_bias) }); m_sp_texture_sampler->SetName("Planet Texture Sampler"); + + // Initialize default uniforms to be ready to render right away + Update(0.0, 0.0); } -gfx::Program::ResourceBindings::Ptr Planet::CreateResourceBindings(const gfx::Buffer::Ptr& sp_constants_buffer, const gfx::Buffer::Ptr& sp_uniforms_buffer) +Ptr Planet::CreateProgramBindings(const Ptr& sp_constants_buffer, const Ptr& sp_uniforms_buffer) { ITT_FUNCTION_TASK(); assert(!!m_sp_state); assert(!!m_sp_state->GetSettings().sp_program); - return gfx::Program::ResourceBindings::Create(m_sp_state->GetSettings().sp_program, { - { { gfx::Shader::Type::All, "g_uniforms" }, { { sp_uniforms_buffer } } }, - { { gfx::Shader::Type::Pixel, "g_constants" }, { { sp_constants_buffer } } }, - { { gfx::Shader::Type::Pixel, "g_texture" }, { { m_mesh_buffers.GetSubsetTexturePtr() } } }, - { { gfx::Shader::Type::Pixel, "g_sampler" }, { { m_sp_texture_sampler } } }, + return gfx::ProgramBindings::Create(m_sp_state->GetSettings().sp_program, { + { { gfx::Shader::Type::All, "g_uniforms" }, { { sp_uniforms_buffer } } }, + { { gfx::Shader::Type::Pixel, "g_constants" }, { { sp_constants_buffer } } }, + { { gfx::Shader::Type::Pixel, "g_texture" }, { { m_mesh_buffers.GetTexturePtr() } } }, + { { gfx::Shader::Type::Pixel, "g_sampler" }, { { m_sp_texture_sampler } } }, }); } @@ -143,9 +149,9 @@ void Planet::Draw(gfx::RenderCommandList& cmd_list, gfx::MeshBufferBindings& buf cmd_list.Reset(m_sp_state, "Planet rendering"); - assert(!buffer_bindings.resource_bindings_per_instance.empty()); - assert(!!buffer_bindings.resource_bindings_per_instance[0]); - m_mesh_buffers.Draw(cmd_list, *buffer_bindings.resource_bindings_per_instance[0]); + assert(!buffer_bindings.program_bindings_per_instance.empty()); + assert(!!buffer_bindings.program_bindings_per_instance[0]); + m_mesh_buffers.Draw(cmd_list, *buffer_bindings.program_bindings_per_instance[0]); } } // namespace Methane::Graphics diff --git a/Apps/Samples/Asteroids/Planet.h b/Apps/Samples/Asteroids/Planet.h index 9a725d079..ddfd2e34d 100644 --- a/Apps/Samples/Asteroids/Planet.h +++ b/Apps/Samples/Asteroids/Planet.h @@ -24,7 +24,7 @@ Planet rendering primitive #pragma once #include -#include +#include #include #include #include @@ -32,6 +32,7 @@ Planet rendering primitive #include #include #include +#include #include @@ -43,8 +44,6 @@ namespace gfx = Graphics; class Planet { public: - using Ptr = std::shared_ptr; - struct Settings { const gfx::Camera& view_camera; @@ -66,9 +65,9 @@ class Planet SHADER_FIELD_ALIGN gfx::Matrix44f model_matrix; }; - Planet(gfx::Context& context, gfx::ImageLoader& image_loader, const Settings& settings); + Planet(gfx::RenderContext& context, gfx::ImageLoader& image_loader, const Settings& settings); - gfx::Program::ResourceBindings::Ptr CreateResourceBindings(const gfx::Buffer::Ptr& sp_constants_buffer, const gfx::Buffer::Ptr& sp_uniforms_buffer); + Ptr CreateProgramBindings(const Ptr& sp_constants_buffer, const Ptr& sp_uniforms_buffer); void Resize(const gfx::FrameSize& frame_size); bool Update(double elapsed_seconds, double delta_seconds); void Draw(gfx::RenderCommandList& cmd_list, gfx::MeshBufferBindings& buffer_bindings); @@ -76,11 +75,26 @@ class Planet private: using TexturedMeshBuffers = gfx::TexturedMeshBuffers; + struct Vertex + { + gfx::Mesh::Position position; + gfx::Mesh::Normal normal; + gfx::Mesh::TexCoord texcoord; + + inline static const gfx::Mesh::VertexLayout layout = { + gfx::Mesh::VertexField::Position, + gfx::Mesh::VertexField::Normal, + gfx::Mesh::VertexField::TexCoord, + }; + }; + + Planet(gfx::RenderContext& context, gfx::ImageLoader& image_loader, const Settings& settings, gfx::BaseMesh mesh); + Settings m_settings; - gfx::Context& m_context; + gfx::RenderContext& m_context; TexturedMeshBuffers m_mesh_buffers; - gfx::Sampler::Ptr m_sp_texture_sampler; - gfx::RenderState::Ptr m_sp_state; + Ptr m_sp_texture_sampler; + Ptr m_sp_state; }; } // namespace Methane::Graphics diff --git a/Apps/Samples/Asteroids/Screenshots/AsteroidsMacMetal.jpg b/Apps/Samples/Asteroids/Screenshots/AsteroidsMacMetal.jpg index 85380945e..74244b770 100644 Binary files a/Apps/Samples/Asteroids/Screenshots/AsteroidsMacMetal.jpg and b/Apps/Samples/Asteroids/Screenshots/AsteroidsMacMetal.jpg differ diff --git a/Apps/Samples/Asteroids/Screenshots/AsteroidsWinCpuTrace.jpg b/Apps/Samples/Asteroids/Screenshots/AsteroidsWinCpuTrace.jpg new file mode 100644 index 000000000..1b8ff3a67 Binary files /dev/null and b/Apps/Samples/Asteroids/Screenshots/AsteroidsWinCpuTrace.jpg differ diff --git a/Apps/Samples/Asteroids/Screenshots/AsteroidsWinDirectX12.jpg b/Apps/Samples/Asteroids/Screenshots/AsteroidsWinDirectX12.jpg index 5c3ccda48..383be0374 100644 Binary files a/Apps/Samples/Asteroids/Screenshots/AsteroidsWinDirectX12.jpg and b/Apps/Samples/Asteroids/Screenshots/AsteroidsWinDirectX12.jpg differ diff --git a/Apps/Samples/Asteroids/Shaders/Asteroids.hlsl b/Apps/Samples/Asteroids/Shaders/Asteroids.hlsl index a10420bab..e8c39d824 100644 --- a/Apps/Samples/Asteroids/Shaders/Asteroids.hlsl +++ b/Apps/Samples/Asteroids/Shaders/Asteroids.hlsl @@ -1,5 +1,33 @@ -// Required macro definitions: -// #define TEXTURES_COUNT 10 +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: MethaneKit/Apps/Samples/Asteroids/Shaders/Asteroids.hlsl +Shaders for asteroids rendering with tri-planar texturing and Phong lighting. +Asteroid textures can be bound indirectly with array of textures and selected +using uniform texture index or bound directly with descriptor table. + +Optional macro definition: TEXTURES_COUNT=10 + +******************************************************************************/ + +#ifndef TEXTURES_COUNT +#define TEXTURES_COUNT 1 +#endif struct VSInput { @@ -63,7 +91,7 @@ PSInput AsteroidVS(VSInput input) output.world_normal = normalize(mul(g_mesh_uniforms.model_matrix, float4(input.normal, 0.0)).xyz); output.albedo = lerp(g_mesh_uniforms.deep_color, g_mesh_uniforms.shallow_color, depth); - // Prepare coordinates and blending weights for triplanar projection texturing + // Prepare coordinates and blending weights for tri-planar projection texturing output.uvw = input.position / g_mesh_uniforms.depth_range.y * 0.5f + 0.5f; output.face_blend_weights = abs(normalize(input.position)); output.face_blend_weights = saturate((output.face_blend_weights - 0.2f) * 7.0f); @@ -78,7 +106,7 @@ float4 AsteroidPS(PSInput input) : SV_TARGET const float3 fragment_to_eye = normalize(g_scene_uniforms.eye_position.xyz - input.world_position); const float3 light_reflected_from_fragment = reflect(-fragment_to_light, input.world_normal); - // Triplanar projection sampling + // Tri-planar projection sampling float3 texel_rgb = 0.0; const uint tex_index = g_mesh_uniforms.texture_index; texel_rgb += input.face_blend_weights.x * g_face_textures[tex_index].Sample(g_texture_sampler, float3(input.uvw.yz, 0)).xyz; diff --git a/Apps/Samples/Asteroids/Shaders/Planet.hlsl b/Apps/Samples/Asteroids/Shaders/Planet.hlsl index bc4921d2e..283f7b80b 100644 --- a/Apps/Samples/Asteroids/Shaders/Planet.hlsl +++ b/Apps/Samples/Asteroids/Shaders/Planet.hlsl @@ -1,3 +1,26 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: MethaneKit/Apps/Samples/Asteroids/Shaders/Planet.hlsl +Shaders for planet rendering with spheric texture and Phong lighting. + +******************************************************************************/ + struct VSInput { float3 position : POSITION; diff --git a/Apps/Tutorials/01-HelloTriangle/CMakeLists.txt b/Apps/Tutorials/01-HelloTriangle/CMakeLists.txt index aabf3df19..c653b585e 100644 --- a/Apps/Tutorials/01-HelloTriangle/CMakeLists.txt +++ b/Apps/Tutorials/01-HelloTriangle/CMakeLists.txt @@ -18,10 +18,10 @@ add_methane_application(${TARGET} "Methane Hello Triangle" "Hello World tutorial of colored triangle rendering with Methane Kit." "${METHANE_COPYRIGHT}" - "${METHANE_VERSION}" - "${METHANE_BUILD_NUMBER}" + "${METHANE_VERSION_SHORT}" + "${METHANE_VERSION_BUILD}" ) -add_methane_shaders(${TARGET} "${SHADERS_HLSL}") +add_methane_shaders(${TARGET} "${SHADERS_HLSL}" "6_0") set_target_properties(${TARGET} PROPERTIES @@ -39,10 +39,10 @@ add_methane_application(${TARGET_SIMPLE} "Methane Hello Triangle" "Hello World tutorial of the colored triangle rendering with Methane Kit." "${METHANE_COPYRIGHT}" - "${METHANE_VERSION}" - "${METHANE_BUILD_NUMBER}" + "${METHANE_VERSION_SHORT}" + "${METHANE_VERSION_BUILD}" ) -add_methane_shaders(${TARGET_SIMPLE} "${SHADERS_HLSL}") +add_methane_shaders(${TARGET_SIMPLE} "${SHADERS_HLSL}" "6_0") set_target_properties(${TARGET_SIMPLE} PROPERTIES diff --git a/Apps/Tutorials/01-HelloTriangle/HelloTriangleApp.cpp b/Apps/Tutorials/01-HelloTriangle/HelloTriangleApp.cpp index 8381ed7ac..08bc2210d 100644 --- a/Apps/Tutorials/01-HelloTriangle/HelloTriangleApp.cpp +++ b/Apps/Tutorials/01-HelloTriangle/HelloTriangleApp.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,39 +23,36 @@ Tutorial demonstrating triangle rendering with Methane graphics API #include "HelloTriangleApp.h" -#include - namespace Methane::Tutorials { -static const gfx::Shader::EntryFunction g_vs_main = { "Triangle", "TriangleVS" }; -static const gfx::Shader::EntryFunction g_ps_main = { "Triangle", "TrianglePS" }; -static const GraphicsApp::Settings g_app_settings = // Application settings: -{ // ==================== - { // app: - "Methane Hello Triangle", // - name - 0.8, 0.8, // - width, height - }, // - { // context: - gfx::FrameSize(), // - frame_size placeholder: actual size is set in InitContext - gfx::PixelFormat::BGRA8Unorm, // - color_format - gfx::PixelFormat::Unknown, // - depth_stencil_format - gfx::Color4f(0.0f, 0.2f, 0.4f, 1.0f), // - clear_color - { /* no depth-stencil clearing */ }, // - clear_depth_stencil - 3, // - frame_buffers_count - true, // - vsync_enabled - }, // - true, // show_hud_in_window_title - true // show_logo_badge +static const GraphicsApp::AllSettings g_app_settings = // Application settings: +{ // ==================== + { // platform_apps: + "Methane Hello Triangle", // - name + 0.8, 0.8, // - width, height + }, // + { // graphics_app: + gfx::RenderPass::Access::ShaderResources | // - screen_pass_access + gfx::RenderPass::Access::Samplers, // + true, // - animations_enabled + true, // - show_hud_in_window_title + true, // - show_logo_badge + 0 // - default_device_index + }, // + { // render_context: + gfx::FrameSize(), // - frame_size placeholder: actual size is set in InitContext + gfx::PixelFormat::BGRA8Unorm, // - color_format + gfx::PixelFormat::Unknown, // - depth_stencil_format + gfx::Color4f(0.0f, 0.2f, 0.4f, 1.0f), // - clear_color + { /* no depth-stencil clearing */ }, // - clear_depth_stencil + 3, // - frame_buffers_count + false, // - vsync_enabled + } }; HelloTriangleApp::HelloTriangleApp() - : GraphicsApp(g_app_settings, gfx::RenderPass::Access::ShaderResources | gfx::RenderPass::Access::Samplers) - , m_triangle_vertices({{ - { { 0.0f, 0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f } }, - { { 0.5f, -0.5f, 0.0f }, { 0.0f, 1.0f, 0.0f } }, - { { -0.5f, -0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f } }, - }}) + : GraphicsApp(g_app_settings, "Methane tutorial of simple triangle rendering") { } @@ -69,31 +66,61 @@ void HelloTriangleApp::Init() { GraphicsApp::Init(); - assert(m_sp_context); - - // Create triangle shading program - m_sp_program = gfx::Program::Create(*m_sp_context, { - { // shaders - gfx::Shader::CreateVertex(*m_sp_context, { Data::ShaderProvider::Get(), g_vs_main }), - gfx::Shader::CreatePixel( *m_sp_context, { Data::ShaderProvider::Get(), g_ps_main }), - }, - { // input_buffer_layouts - { // single vertex buffer layout with interleaved data - { // input arguments mapping to semantic names - { "input_position", "POSITION" }, - { "input_color", "COLOR" }, + struct Vertex + { + gfx::Vector3f position; + gfx::Vector3f color; + }; + + const std::array triangle_vertices = {{ + { { 0.0f, 0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f } }, + { { 0.5f, -0.5f, 0.0f }, { 0.0f, 1.0f, 0.0f } }, + { { -0.5f, -0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f } }, + }}; + + // Create vertex buffer with triangle data + const Data::Size vertex_size = static_cast(sizeof(Vertex)); + const Data::Size vertex_data_size = static_cast(sizeof(triangle_vertices)); + + m_sp_vertex_buffer = gfx::Buffer::CreateVertexBuffer(*m_sp_context, vertex_data_size, vertex_size); + m_sp_vertex_buffer->SetName("Triangle Vertex Buffer"); + m_sp_vertex_buffer->SetData({ { reinterpret_cast(triangle_vertices.data()), vertex_data_size } }); + + // Create render state + m_sp_state = gfx::RenderState::Create(*m_sp_context, + gfx::RenderState::Settings + { + gfx::Program::Create(*m_sp_context, + gfx::Program::Settings + { + gfx::Program::Shaders + { + gfx::Shader::CreateVertex(*m_sp_context, { Data::ShaderProvider::Get(), { "Triangle", "TriangleVS" } }), + gfx::Shader::CreatePixel( *m_sp_context, { Data::ShaderProvider::Get(), { "Triangle", "TrianglePS" } }), + }, + gfx::Program::InputBufferLayouts + { + gfx::Program::InputBufferLayout + { + gfx::Program::InputBufferLayout::ArgumentSemantics { "POSITION" , "COLOR" } + } + }, + gfx::Program::ArgumentDescriptions { }, + gfx::PixelFormats { m_sp_context->GetSettings().color_format } } - } - }, - { // constant_argument_names - }, - { // addressable_argument_names - }, - { // render_target_pixel_formats - GetInitialContextSettings().color_format + ), + gfx::Viewports + { + gfx::GetFrameViewport(GetInitialContextSettings().frame_size) + }, + gfx::ScissorRects + { + gfx::GetFrameScissorRect(GetInitialContextSettings().frame_size) + }, } - }); - m_sp_program->SetName("Colored Vertices"); + ); + m_sp_state->GetSettings().sp_program->SetName("Colored Triangle Shading"); + m_sp_state->SetName("Triangle Pipeline State"); // Create per-frame command lists for(HelloTriangleFrame& frame : m_frames) @@ -102,22 +129,6 @@ void HelloTriangleApp::Init() frame.sp_cmd_list->SetName(IndexedName("Triangle Rendering", frame.index)); } - // Create vertex buffer with triangle data - const Data::Size vertex_size = static_cast(sizeof(Vertex)); - const Data::Size vertex_data_size = static_cast(sizeof(m_triangle_vertices)); - - m_sp_vertex_buffer = gfx::Buffer::CreateVertexBuffer(*m_sp_context, vertex_data_size, vertex_size); - m_sp_vertex_buffer->SetName("Triangle Vertex Buffer"); - m_sp_vertex_buffer->SetData({ { reinterpret_cast(m_triangle_vertices.data()), vertex_data_size } }); - - // Create render state - m_sp_state = gfx::RenderState::Create(*m_sp_context, { - m_sp_program, - { gfx::GetFrameViewport(GetInitialContextSettings().frame_size) }, - { gfx::GetFrameScissorRect(GetInitialContextSettings().frame_size) }, - }); - m_sp_state->SetName("Frame Render Pipeline State"); - // Complete initialization of render context m_sp_context->CompleteInitialization(); } @@ -129,7 +140,6 @@ bool HelloTriangleApp::Resize(const gfx::FrameSize& frame_size, bool is_minimize return false; // Update viewports and scissor rects state - assert(m_sp_state); m_sp_state->SetViewports( { gfx::GetFrameViewport(frame_size) } ); m_sp_state->SetScissorRects( { gfx::GetFrameScissorRect(frame_size) } ); @@ -139,7 +149,6 @@ bool HelloTriangleApp::Resize(const gfx::FrameSize& frame_size, bool is_minimize bool HelloTriangleApp::Render() { // Render only when context is ready - assert(!!m_sp_context); if (!m_sp_context->ReadyToRender() || !GraphicsApp::Render()) return false; @@ -147,19 +156,15 @@ bool HelloTriangleApp::Render() m_sp_context->WaitForGpu(gfx::Context::WaitFor::FramePresented); HelloTriangleFrame& frame = GetCurrentFrame(); - assert(!!frame.sp_cmd_list); - assert(!!m_sp_vertex_buffer); - assert(!!m_sp_state); - // Issue commands for triangle rendering - frame.sp_cmd_list->Reset(m_sp_state, "Cube redering"); + frame.sp_cmd_list->Reset(m_sp_state, "Triangle Rendering"); frame.sp_cmd_list->SetVertexBuffers({ *m_sp_vertex_buffer }); - frame.sp_cmd_list->Draw(gfx::RenderCommandList::Primitive::Triangle, static_cast(m_triangle_vertices.size())); + frame.sp_cmd_list->Draw(gfx::RenderCommandList::Primitive::Triangle, 3u); RenderOverlay(*frame.sp_cmd_list); // Commit command list with present flag - frame.sp_cmd_list->Commit(true); + frame.sp_cmd_list->Commit(); // Execute command list on render queue and present frame to screen m_sp_context->GetRenderCommandQueue().Execute({ *frame.sp_cmd_list }); @@ -172,7 +177,6 @@ void HelloTriangleApp::OnContextReleased() { m_sp_vertex_buffer.reset(); m_sp_state.reset(); - m_sp_program.reset(); GraphicsApp::OnContextReleased(); } diff --git a/Apps/Tutorials/01-HelloTriangle/HelloTriangleApp.h b/Apps/Tutorials/01-HelloTriangle/HelloTriangleApp.h index cfbc635a4..5a1b700f0 100644 --- a/Apps/Tutorials/01-HelloTriangle/HelloTriangleApp.h +++ b/Apps/Tutorials/01-HelloTriangle/HelloTriangleApp.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -35,7 +35,7 @@ namespace gfx = Methane::Graphics; struct HelloTriangleFrame final : gfx::AppFrame { - gfx::RenderCommandList::Ptr sp_cmd_list; + Ptr sp_cmd_list; using gfx::AppFrame::AppFrame; }; @@ -48,7 +48,7 @@ class HelloTriangleApp final : public GraphicsApp HelloTriangleApp(); ~HelloTriangleApp() override; - // App interface + // GraphicsApp overrides void Init() override; bool Resize(const gfx::FrameSize& frame_size, bool is_minimized) override; bool Render() override; @@ -57,18 +57,8 @@ class HelloTriangleApp final : public GraphicsApp void OnContextReleased() override; private: - struct Vertex - { - gfx::Vector3f position; - gfx::Vector3f color; - }; - - using Vertices = std::array; - const Vertices m_triangle_vertices; - - gfx::Program::Ptr m_sp_program; - gfx::RenderState::Ptr m_sp_state; - gfx::Buffer::Ptr m_sp_vertex_buffer; + Ptr m_sp_state; + Ptr m_sp_vertex_buffer; }; } // namespace Methane::Tutorials diff --git a/Apps/Tutorials/01-HelloTriangle/HelloTriangleAppSimple.cpp b/Apps/Tutorials/01-HelloTriangle/HelloTriangleAppSimple.cpp index 147b36b47..a65a61beb 100644 --- a/Apps/Tutorials/01-HelloTriangle/HelloTriangleAppSimple.cpp +++ b/Apps/Tutorials/01-HelloTriangle/HelloTriangleAppSimple.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ using namespace Methane::Graphics; struct HelloTriangleFrame final : AppFrame { - RenderCommandList::Ptr sp_cmd_list; + Ptr sp_cmd_list; using AppFrame::AppFrame; }; @@ -36,26 +36,29 @@ using GraphicsApp = App; class HelloTriangleApp final : public GraphicsApp { private: - RenderState::Ptr m_sp_state; - Buffer::Ptr m_sp_vertex_buffer; + Ptr m_sp_state; + Ptr m_sp_vertex_buffer; public: HelloTriangleApp() : GraphicsApp( { // Application settings: - { // app: + { // platform_app: "Methane Hello Triangle", // - name 0.8, 0.8, // - width, height }, // - { // context: + { // graphics_app: + RenderPass::Access::None, // - screen_pass_access + false, // - animations_enabled + true, // - show_hud_in_window_title + false, // - show_logo_badge + }, // + { // render_context: FrameSize(), // - frame_size placeholder: actual size is set in InitContext PixelFormat::BGRA8Unorm, // - color_format PixelFormat::Unknown, // - depth_stencil_format Color4f(0.0f, 0.2f, 0.4f, 1.0f), // - clear_color - }, // - true, // show_hud_in_window_title - false // show_logo_badge - }, - RenderPass::Access::None) // screen_pass_access (program access to resources) + } + }) { } ~HelloTriangleApp() override @@ -68,33 +71,47 @@ class HelloTriangleApp final : public GraphicsApp GraphicsApp::Init(); struct Vertex { Vector3f position; Vector3f color; }; - const std::array triange_vertices = { { + const std::array triangle_vertices = { { { { 0.0f, 0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f } }, { { 0.5f, -0.5f, 0.0f }, { 0.0f, 1.0f, 0.0f } }, { { -0.5f, -0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f } }, } }; - const Data::Size vertex_buffer_size = static_cast(sizeof(triange_vertices)); + const Data::Size vertex_buffer_size = static_cast(sizeof(triangle_vertices)); m_sp_vertex_buffer = Buffer::CreateVertexBuffer(*m_sp_context, vertex_buffer_size, static_cast(sizeof(Vertex))); - m_sp_vertex_buffer->SetData({ { reinterpret_cast(triange_vertices.data()), vertex_buffer_size } }); + m_sp_vertex_buffer->SetData( + Resource::SubResources + { + Resource::SubResource { reinterpret_cast(triangle_vertices.data()), vertex_buffer_size } + } + ); m_sp_state = RenderState::Create(*m_sp_context, - { - Program::Create(*m_sp_context, { - { - Shader::CreateVertex(*m_sp_context, { Data::ShaderProvider::Get(), { "Triangle", "TriangleVS" } }), - Shader::CreatePixel(*m_sp_context, { Data::ShaderProvider::Get(), { "Triangle", "TrianglePS" } }), - }, - { { { - { "input_position", "POSITION" }, - { "input_color", "COLOR" }, - } } }, - { }, { }, - { m_sp_context->GetSettings().color_format } - }), - { GetFrameViewport(m_sp_context->GetSettings().frame_size) }, - { GetFrameScissorRect(m_sp_context->GetSettings().frame_size) }, - }); + RenderState::Settings + { + Program::Create(*m_sp_context, + Program::Settings + { + Program::Shaders + { + Shader::CreateVertex(*m_sp_context, { Data::ShaderProvider::Get(), { "Triangle", "TriangleVS" } }), + Shader::CreatePixel(*m_sp_context, { Data::ShaderProvider::Get(), { "Triangle", "TrianglePS" } }), + }, + Program::InputBufferLayouts + { + Program::InputBufferLayout + { + Program::InputBufferLayout::ArgumentSemantics { "POSITION", "COLOR" }, + } + }, + Program::ArgumentDescriptions { }, + PixelFormats { m_sp_context->GetSettings().color_format } + } + ), + Viewports { GetFrameViewport(m_sp_context->GetSettings().frame_size) }, + ScissorRects { GetFrameScissorRect(m_sp_context->GetSettings().frame_size) }, + } + ); for (HelloTriangleFrame& frame : m_frames) { @@ -125,7 +142,7 @@ class HelloTriangleApp final : public GraphicsApp frame.sp_cmd_list->Reset(m_sp_state); frame.sp_cmd_list->SetVertexBuffers({ *m_sp_vertex_buffer }); frame.sp_cmd_list->Draw(RenderCommandList::Primitive::Triangle, 3); - frame.sp_cmd_list->Commit(true); + frame.sp_cmd_list->Commit(); m_sp_context->GetRenderCommandQueue().Execute({ *frame.sp_cmd_list }); m_sp_context->Present(); diff --git a/Apps/Tutorials/01-HelloTriangle/Shaders/Triangle.hlsl b/Apps/Tutorials/01-HelloTriangle/Shaders/Triangle.hlsl index c92b74dc4..5de384eaf 100644 --- a/Apps/Tutorials/01-HelloTriangle/Shaders/Triangle.hlsl +++ b/Apps/Tutorials/01-HelloTriangle/Shaders/Triangle.hlsl @@ -1,3 +1,26 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: MethaneKit/Apps/Tutorials/01-HelloTriangle/Shaders/Triangle.hlsl +Shaders for colored triangle rendering + +******************************************************************************/ + struct VSInput { float3 position : POSITION; diff --git a/Apps/Tutorials/02-TexturedCube/CMakeLists.txt b/Apps/Tutorials/02-TexturedCube/CMakeLists.txt index ddf054866..0973a122f 100644 --- a/Apps/Tutorials/02-TexturedCube/CMakeLists.txt +++ b/Apps/Tutorials/02-TexturedCube/CMakeLists.txt @@ -20,11 +20,11 @@ add_methane_application(${TARGET} "Methane Textured Cube" "Tutorial of the textured cube rendering with Methane Kit." "${METHANE_COPYRIGHT}" - "${METHANE_VERSION}" - "${METHANE_BUILD_NUMBER}" + "${METHANE_VERSION_SHORT}" + "${METHANE_VERSION_BUILD}" ) add_methane_embedded_textures(${TARGET} "${IMAGES_DIR}" "${TEXTURES}") -add_methane_shaders(${TARGET} "${SHADERS_HLSL}") +add_methane_shaders(${TARGET} "${SHADERS_HLSL}" "6_0") set_target_properties(${TARGET} PROPERTIES diff --git a/Apps/Tutorials/02-TexturedCube/Shaders/Cube.hlsl b/Apps/Tutorials/02-TexturedCube/Shaders/Cube.hlsl index b13e9346c..67c6636c7 100644 --- a/Apps/Tutorials/02-TexturedCube/Shaders/Cube.hlsl +++ b/Apps/Tutorials/02-TexturedCube/Shaders/Cube.hlsl @@ -1,3 +1,26 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: MethaneKit/Apps/Tutorials/02-TexturedCube/Shaders/Cube.hlsl +Shaders for textured cube rendering with Phong lighting model + +******************************************************************************/ + struct VSInput { float3 position : POSITION; diff --git a/Apps/Tutorials/02-TexturedCube/TexturedCubeApp.cpp b/Apps/Tutorials/02-TexturedCube/TexturedCubeApp.cpp index a174f0b7b..81038425b 100644 --- a/Apps/Tutorials/02-TexturedCube/TexturedCubeApp.cpp +++ b/Apps/Tutorials/02-TexturedCube/TexturedCubeApp.cpp @@ -23,45 +23,61 @@ Tutorial demonstrating textured cube rendering with Methane graphics API #include "TexturedCubeApp.h" +#include #include #include -#include namespace Methane::Tutorials { -static const gfx::Shader::EntryFunction g_vs_main = { "Cube", "CubeVS" }; -static const gfx::Shader::EntryFunction g_ps_main = { "Cube", "CubePS" }; -static const GraphicsApp::Settings g_app_settings = // Application settings: -{ // ==================== - { // app: - "Methane Textured Cube", // - name - 0.8, 0.8, // - width, height - }, // - { // context: - gfx::FrameSize(), // - frame_size - gfx::PixelFormat::BGRA8Unorm, // - color_format - gfx::PixelFormat::Depth32Float, // - depth_stencil_format - gfx::Color4f(0.0f, 0.2f, 0.4f, 1.0f), // - clear_color - gfx::DepthStencil{ 1.f, 0u }, // - clear_depth_stencil - 3, // - frame_buffers_count - true, // - vsync_enabled - }, // - true, // show_hud_in_window_title - true // show_logo_badge +struct CubeVertex +{ + gfx::Mesh::Position position; + gfx::Mesh::Normal normal; + gfx::Mesh::TexCoord texcoord; + + inline static const gfx::Mesh::VertexLayout layout = { + gfx::Mesh::VertexField::Position, + gfx::Mesh::VertexField::Normal, + gfx::Mesh::VertexField::TexCoord, + }; +}; + +static const GraphicsApp::AllSettings g_app_settings = // Application settings: +{ // ==================== + { // platform_app: + "Methane Textured Cube", // - name + 0.8, 0.8, // - width, height + }, // + { // graphics_app: + gfx::RenderPass::Access::ShaderResources | // - screen_pass_access + gfx::RenderPass::Access::Samplers, // + true, // - animations_enabled + true, // - show_hud_in_window_title + true, // - show_logo_badge + 0 // - default_device_index + }, // + { // render_context: + gfx::FrameSize(), // - frame_size + gfx::PixelFormat::BGRA8Unorm, // - color_format + gfx::PixelFormat::Depth32Float, // - depth_stencil_format + gfx::Color4f(0.0f, 0.2f, 0.4f, 1.0f), // - clear_color + gfx::DepthStencil{ 1.f, 0 }, // - clear_depth_stencil + 3, // - frame_buffers_count + false, // - vsync_enabled + } }; TexturedCubeApp::TexturedCubeApp() - : GraphicsApp(g_app_settings, gfx::RenderPass::Access::ShaderResources | gfx::RenderPass::Access::Samplers) - , m_shader_constants( // Shader constants: - { // ================ - gfx::Color4f(1.f, 1.f, 0.74f, 1.f), // - light_color - 700.f, // - light_power - 0.2f, // - light_ambient_factor - 5.f // - light_specular_factor + : GraphicsApp(g_app_settings, "Methane tutorial of textured cube rendering") + , m_shader_constants( // Shader constants: + { // ================ + gfx::Color4f(1.f, 1.f, 0.74f, 1.f), // - light_color + 700.f, // - light_power + 0.2f, // - light_ambient_factor + 5.f // - light_specular_factor }) - , m_cube_mesh(gfx::Mesh::VertexLayoutFromArray(Vertex::layout)) , m_cube_scale(15.f) { m_shader_uniforms.light_position = gfx::Vector3f(0.f, 20.f, -25.f); @@ -82,58 +98,86 @@ TexturedCubeApp::TexturedCubeApp() TexturedCubeApp::~TexturedCubeApp() { // Wait for GPU rendering is completed to release resources - m_sp_context->WaitForGpu(gfx::Context::WaitFor::RenderComplete); + m_sp_context->WaitForGpu(gfx::RenderContext::WaitFor::RenderComplete); } void TexturedCubeApp::Init() { GraphicsApp::Init(); - assert(m_sp_context); - const gfx::Context::Settings& context_settings = m_sp_context->GetSettings(); + const gfx::RenderContext::Settings& context_settings = m_sp_context->GetSettings(); m_camera.Resize(static_cast(context_settings.frame_size.width), static_cast(context_settings.frame_size.height)); - // Create cube shading program - m_sp_program = gfx::Program::Create(*m_sp_context, { - { // shaders - gfx::Shader::CreateVertex(*m_sp_context, { Data::ShaderProvider::Get(), g_vs_main }), - gfx::Shader::CreatePixel( *m_sp_context, { Data::ShaderProvider::Get(), g_ps_main }), - }, - { // input_buffer_layouts - { // single vertex buffer layout with interleaved data - { // input arguments mapping to semantic names - { "input_position", "POSITION" }, - { "input_normal", "NORMAL" }, - { "input_texcoord", "TEXCOORD" }, + const gfx::CubeMesh cube_mesh(CubeVertex::layout); + + // Create render state with program + gfx::RenderState::Settings state_settings; + state_settings.sp_program = gfx::Program::Create(*m_sp_context, + gfx::Program::Settings + { + gfx::Program::Shaders + { + gfx::Shader::CreateVertex(*m_sp_context, { Data::ShaderProvider::Get(), { "Cube", "CubeVS" } }), + gfx::Shader::CreatePixel( *m_sp_context, { Data::ShaderProvider::Get(), { "Cube", "CubePS" } }), + }, + gfx::Program::InputBufferLayouts + { + gfx::Program::InputBufferLayout + { + gfx::Program::InputBufferLayout::ArgumentSemantics { cube_mesh.GetVertexLayout().GetSemantics() } } - } - }, - { // constant_argument_names - "g_constants", "g_texture", "g_sampler" - }, - { // addressable_argument_names - }, - { // render_target_pixel_formats - context_settings.color_format - }, - context_settings.depth_stencil_format - }); - m_sp_program->SetName("Textured Phong Lighting"); + }, + gfx::Program::ArgumentDescriptions + { + { { gfx::Shader::Type::All, "g_uniforms" }, gfx::Program::Argument::Modifiers::None }, + { { gfx::Shader::Type::Pixel, "g_constants" }, gfx::Program::Argument::Modifiers::Constant }, + { { gfx::Shader::Type::Pixel, "g_texture" }, gfx::Program::Argument::Modifiers::Constant }, + { { gfx::Shader::Type::Pixel, "g_sampler" }, gfx::Program::Argument::Modifiers::Constant }, + }, + gfx::PixelFormats + { + context_settings.color_format + }, + context_settings.depth_stencil_format + } + ); + state_settings.sp_program->SetName("Textured Phong Lighting"); + state_settings.viewports = { gfx::GetFrameViewport(context_settings.frame_size) }; + state_settings.scissor_rects = { gfx::GetFrameScissorRect(context_settings.frame_size) }; + state_settings.depth.enabled = true; + m_sp_state = gfx::RenderState::Create(*m_sp_context, state_settings); + m_sp_state->SetName("Final FB Render Pipeline State"); // Load texture image from file m_sp_cube_texture = m_image_loader.LoadImageToTexture2D(*m_sp_context, "Textures/MethaneBubbles.jpg", true); m_sp_cube_texture->SetName("Cube Texture 2D Image"); // Create sampler for image texture - m_sp_texture_sampler = gfx::Sampler::Create(*m_sp_context, { - { gfx::Sampler::Filter::MinMag::Linear }, // Bilinear filtering - { gfx::Sampler::Address::Mode::ClampToZero } - }); + m_sp_texture_sampler = gfx::Sampler::Create(*m_sp_context, + gfx::Sampler::Settings + { + gfx::Sampler::Filter { gfx::Sampler::Filter::MinMag::Linear }, + gfx::Sampler::Address { gfx::Sampler::Address::Mode::ClampToEdge } + } + ); const Data::Size constants_data_size = gfx::Buffer::GetAlignedBufferSize(static_cast(sizeof(m_shader_constants))); const Data::Size uniforms_data_size = gfx::Buffer::GetAlignedBufferSize(static_cast(sizeof(m_shader_uniforms))); + // Create vertex buffer for cube mesh + const Data::Size vertex_data_size = static_cast(cube_mesh.GetVertexDataSize()); + const Data::Size vertex_size = static_cast(cube_mesh.GetVertexSize()); + m_sp_vertex_buffer = gfx::Buffer::CreateVertexBuffer(*m_sp_context, vertex_data_size, vertex_size); + m_sp_vertex_buffer->SetName("Cube Vertex Buffer"); + m_sp_vertex_buffer->SetData({ { reinterpret_cast(cube_mesh.GetVertices().data()), vertex_data_size } }); + + // Create index buffer for cube mesh + const Data::Size index_data_size = static_cast(cube_mesh.GetIndexDataSize()); + m_sp_index_buffer = gfx::Buffer::CreateIndexBuffer(*m_sp_context, index_data_size, gfx::GetIndexFormat(cube_mesh.GetIndex(0))); + m_sp_index_buffer->SetName("Cube Index Buffer"); + m_sp_index_buffer->SetData({ { reinterpret_cast(cube_mesh.GetIndices().data()), index_data_size } }); + // Create constants buffer for frame rendering m_sp_const_buffer = gfx::Buffer::CreateConstantBuffer(*m_sp_context, constants_data_size); m_sp_const_buffer->SetName("Constants Buffer"); @@ -147,7 +191,7 @@ void TexturedCubeApp::Init() frame.sp_uniforms_buffer->SetName(IndexedName("Uniforms Buffer", frame.index)); // Configure program resource bindings - frame.sp_resource_bindings = gfx::Program::ResourceBindings::Create(m_sp_program, { + frame.sp_program_bindings = gfx::ProgramBindings::Create(state_settings.sp_program, { { { gfx::Shader::Type::All, "g_uniforms" }, { { frame.sp_uniforms_buffer } } }, { { gfx::Shader::Type::Pixel, "g_constants" }, { { m_sp_const_buffer } } }, { { gfx::Shader::Type::Pixel, "g_texture" }, { { m_sp_cube_texture } } }, @@ -159,28 +203,6 @@ void TexturedCubeApp::Init() frame.sp_cmd_list->SetName(IndexedName("Cube Rendering", frame.index)); } - // Create vertex buffer for cube mesh - const Data::Size vertex_data_size = static_cast(m_cube_mesh.GetVertexDataSize()); - const Data::Size vertex_size = static_cast(m_cube_mesh.GetVertexSize()); - m_sp_vertex_buffer = gfx::Buffer::CreateVertexBuffer(*m_sp_context, vertex_data_size, vertex_size); - m_sp_vertex_buffer->SetName("Cube Vertex Buffer"); - m_sp_vertex_buffer->SetData({ { reinterpret_cast(m_cube_mesh.GetVertices().data()), vertex_data_size } }); - - // Create index buffer for cube mesh - const Data::Size index_data_size = static_cast(m_cube_mesh.GetIndexDataSize()); - m_sp_index_buffer = gfx::Buffer::CreateIndexBuffer(*m_sp_context, index_data_size, gfx::GetIndexFormat(m_cube_mesh.GetIndex(0))); - m_sp_index_buffer->SetName("Cube Index Buffer"); - m_sp_index_buffer->SetData({ { reinterpret_cast(m_cube_mesh.GetIndices().data()), index_data_size } }); - - // Create render state - gfx::RenderState::Settings state_settings; - state_settings.sp_program = m_sp_program; - state_settings.viewports = { gfx::GetFrameViewport(context_settings.frame_size) }; - state_settings.scissor_rects = { gfx::GetFrameScissorRect(context_settings.frame_size) }; - state_settings.depth.enabled = true; - m_sp_state = gfx::RenderState::Create(*m_sp_context, state_settings); - m_sp_state->SetName("Final FB Render Pipeline State"); - // Complete initialization of render context: // - allocate deferred descriptor heaps with calculated sizes // - execute commands to upload resources to GPU @@ -194,7 +216,6 @@ bool TexturedCubeApp::Resize(const gfx::FrameSize& frame_size, bool is_minimized return false; // Update viewports and scissor rects state - assert(m_sp_state); m_sp_state->SetViewports({ gfx::GetFrameViewport(frame_size) }); m_sp_state->SetScissorRects({ gfx::GetFrameScissorRect(frame_size) }); @@ -224,34 +245,26 @@ bool TexturedCubeApp::Update() bool TexturedCubeApp::Render() { // Render only when context is ready - assert(!!m_sp_context); if (!m_sp_context->ReadyToRender() || !GraphicsApp::Render()) return false; // Wait for previous frame rendering is completed and switch to next frame - m_sp_context->WaitForGpu(gfx::Context::WaitFor::FramePresented); + m_sp_context->WaitForGpu(gfx::RenderContext::WaitFor::FramePresented); TexturedCubeFrame& frame = GetCurrentFrame(); - assert(!!frame.sp_uniforms_buffer); - assert(!!frame.sp_cmd_list); - assert(!!frame.sp_resource_bindings); - assert(!!m_sp_vertex_buffer); - assert(!!m_sp_index_buffer); - assert(!!m_sp_state); - // Update uniforms buffer related to current frame frame.sp_uniforms_buffer->SetData({ { reinterpret_cast(&m_shader_uniforms), sizeof(Uniforms) } }); // Issue commands for cube rendering - frame.sp_cmd_list->Reset(m_sp_state, "Cube redering"); - frame.sp_cmd_list->SetResourceBindings(*frame.sp_resource_bindings); + frame.sp_cmd_list->Reset(m_sp_state, "Cube Rendering"); + frame.sp_cmd_list->SetProgramBindings(*frame.sp_program_bindings); frame.sp_cmd_list->SetVertexBuffers({ *m_sp_vertex_buffer }); frame.sp_cmd_list->DrawIndexed(gfx::RenderCommandList::Primitive::Triangle, *m_sp_index_buffer); RenderOverlay(*frame.sp_cmd_list); // Commit command list with present flag - frame.sp_cmd_list->Commit(true); + frame.sp_cmd_list->Commit(); // Execute command list on render queue and present frame to screen m_sp_context->GetRenderCommandQueue().Execute({ *frame.sp_cmd_list }); @@ -268,7 +281,6 @@ void TexturedCubeApp::OnContextReleased() m_sp_index_buffer.reset(); m_sp_vertex_buffer.reset(); m_sp_state.reset(); - m_sp_program.reset(); GraphicsApp::OnContextReleased(); } diff --git a/Apps/Tutorials/02-TexturedCube/TexturedCubeApp.h b/Apps/Tutorials/02-TexturedCube/TexturedCubeApp.h index 34ac44f7d..dcddbdc56 100644 --- a/Apps/Tutorials/02-TexturedCube/TexturedCubeApp.h +++ b/Apps/Tutorials/02-TexturedCube/TexturedCubeApp.h @@ -37,9 +37,9 @@ namespace dat = Methane::Data; struct TexturedCubeFrame final : gfx::AppFrame { - gfx::Buffer::Ptr sp_uniforms_buffer; - gfx::Program::ResourceBindings::Ptr sp_resource_bindings; - gfx::RenderCommandList::Ptr sp_cmd_list; + Ptr sp_uniforms_buffer; + Ptr sp_program_bindings; + Ptr sp_cmd_list; using gfx::AppFrame::AppFrame; }; @@ -52,30 +52,16 @@ class TexturedCubeApp final : public GraphicsApp TexturedCubeApp(); ~TexturedCubeApp() override; - // App interface + // GraphicsApp overrides void Init() override; bool Resize(const gfx::FrameSize& frame_size, bool is_minimized) override; bool Update() override; bool Render() override; - // Context::Callback interface + // Context::Callback override void OnContextReleased() override; private: - struct Vertex - { - gfx::Mesh::Position position; - gfx::Mesh::Normal normal; - gfx::Mesh::TexCoord texcoord; - - using FieldsArray = std::array; - static constexpr const FieldsArray layout = { - gfx::Mesh::VertexField::Position, - gfx::Mesh::VertexField::Normal, - gfx::Mesh::VertexField::TexCoord, - }; - }; - struct SHADER_STRUCT_ALIGN Constants { SHADER_FIELD_ALIGN gfx::Color4f light_color; @@ -93,18 +79,15 @@ class TexturedCubeApp final : public GraphicsApp }; const Constants m_shader_constants; - Uniforms m_shader_uniforms; + Uniforms m_shader_uniforms = { }; gfx::Camera m_camera; - gfx::BoxMesh m_cube_mesh; float m_cube_scale; - gfx::Program::Ptr m_sp_program; - gfx::RenderState::Ptr m_sp_state; - gfx::Buffer::Ptr m_sp_vertex_buffer; - gfx::Buffer::Ptr m_sp_index_buffer; - gfx::Buffer::Ptr m_sp_const_buffer; - gfx::Texture::Ptr m_sp_cube_texture; - gfx::Sampler::Ptr m_sp_texture_sampler; - + Ptr m_sp_state; + Ptr m_sp_vertex_buffer; + Ptr m_sp_index_buffer; + Ptr m_sp_const_buffer; + Ptr m_sp_cube_texture; + Ptr m_sp_texture_sampler; }; } // namespace Methane::Tutorials diff --git a/Apps/Tutorials/03-ShadowCube/CMakeLists.txt b/Apps/Tutorials/03-ShadowCube/CMakeLists.txt index 66eafa1aa..05d1692e0 100644 --- a/Apps/Tutorials/03-ShadowCube/CMakeLists.txt +++ b/Apps/Tutorials/03-ShadowCube/CMakeLists.txt @@ -23,11 +23,11 @@ add_methane_application(${TARGET} "Methane Shadow Cube" "Tutorial of the shadow pass rendering with Methane Kit." "${METHANE_COPYRIGHT}" - "${METHANE_VERSION}" - "${METHANE_BUILD_NUMBER}" + "${METHANE_VERSION_SHORT}" + "${METHANE_VERSION_BUILD}" ) add_methane_embedded_textures(${TARGET} "${IMAGES_DIR}" "${TEXTURES}") -add_methane_shaders(${TARGET} "${SHADERS_HLSL}") +add_methane_shaders(${TARGET} "${SHADERS_HLSL}" "6_0") set_target_properties(${TARGET} PROPERTIES diff --git a/Apps/Tutorials/03-ShadowCube/Shaders/ShadowCube.hlsl b/Apps/Tutorials/03-ShadowCube/Shaders/ShadowCube.hlsl index ad6a1e2a2..ea63d45e1 100644 --- a/Apps/Tutorials/03-ShadowCube/Shaders/ShadowCube.hlsl +++ b/Apps/Tutorials/03-ShadowCube/Shaders/ShadowCube.hlsl @@ -1,6 +1,29 @@ -// Optional macro definitions: -// #define ENABLE_SHADOWS -// #define ENABLE_TEXTURING +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: MethaneKit/Apps/Tutorials/03-ShadowCube/Shaders/ShadowCube.hlsl +Shaders for shadow and final pass rendering of textured cube +with Phong lighting model and simple shadows + +Optional macro definition: ENABLE_SHADOWS, ENABLE_TEXTURING + +******************************************************************************/ + struct VSInput { @@ -87,7 +110,7 @@ float4 CubePS(PSInput input) : SV_TARGET #ifdef ENABLE_SHADOWS float3 light_proj_pos = input.shadow_position.xyz / input.shadow_position.w; - const float current_depth = light_proj_pos.z - 0.001f; + const float current_depth = light_proj_pos.z - 0.0001f; const float shadow_depth = g_shadow_map.Sample(g_shadow_sampler, light_proj_pos.xy).r; const float shadow_ratio = current_depth > shadow_depth ? 1.0f : 0.0f; #else diff --git a/Apps/Tutorials/03-ShadowCube/ShadowCubeApp.cpp b/Apps/Tutorials/03-ShadowCube/ShadowCubeApp.cpp index 266c7deac..16ecea0fb 100644 --- a/Apps/Tutorials/03-ShadowCube/ShadowCubeApp.cpp +++ b/Apps/Tutorials/03-ShadowCube/ShadowCubeApp.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,41 +23,56 @@ Tutorial demonstrating shadow-pass rendering with Methane graphics API #include "ShadowCubeApp.h" +#include #include #include -#include namespace Methane::Tutorials { +struct Vertex +{ + gfx::Mesh::Position position; + gfx::Mesh::Normal normal; + gfx::Mesh::TexCoord texcoord; + + inline static const gfx::Mesh::VertexLayout layout = { + gfx::Mesh::VertexField::Position, + gfx::Mesh::VertexField::Normal, + gfx::Mesh::VertexField::TexCoord, + }; +}; + // Common application settings -static const gfx::FrameSize g_shadow_map_size(1024, 1024); -static const gfx::Shader::EntryFunction g_vs_main = { "ShadowCube", "CubeVS" }; -static const gfx::Shader::EntryFunction g_ps_main = { "ShadowCube", "CubePS" }; -static const GraphicsApp::Settings g_app_settings = // Application settings: +static const gfx::FrameSize g_shadow_map_size(1024, 1024); +static const GraphicsApp::AllSettings g_app_settings = // Application settings: { // ==================== - { // app: + { // platform_app: "Methane Shadow Cube", // - name 0.8, 0.8, // - width, height }, // - { // context: + { // graphics_app: + gfx::RenderPass::Access::ShaderResources | // - screen_pass_access + gfx::RenderPass::Access::Samplers, // + true, // - animations_enabled + true, // - show_hud_in_window_title + true, // - show_logo_badge + 0 // - default_device_index + }, // + { // render_context: gfx::FrameSize(), // - frame_size gfx::PixelFormat::BGRA8Unorm, // - color_format gfx::PixelFormat::Depth32Float, // - depth_stencil_format gfx::Color4f(0.0f, 0.2f, 0.4f, 1.0f), // - clear_color - gfx::DepthStencil{ 1.f, 0u }, // - clear_depth_stencil + gfx::DepthStencil{ 1.f, 0 }, // - clear_depth_stencil 3, // - frame_buffers_count - true, // - vsync_enabled - }, // - true, // show_hud_in_window_title - true // show_logo_badge + false, // - vsync_enabled + } }; ShadowCubeApp::ShadowCubeApp() - : GraphicsApp(g_app_settings, gfx::RenderPass::Access::ShaderResources | gfx::RenderPass::Access::Samplers) - , m_cube_mesh(gfx::Mesh::VertexLayoutFromArray(Vertex::layout), 1.f, 1.f, 1.f) - , m_floor_mesh(gfx::Mesh::VertexLayoutFromArray(Vertex::layout), 7.f, 7.f, 0.f, 0, gfx::RectMesh::FaceType::XZ) + : GraphicsApp(g_app_settings, "Methane tutorial of shadow pass rendering") , m_scene_scale(15.f) , m_scene_constants( // Shader constants: { // ================ @@ -66,12 +81,14 @@ ShadowCubeApp::ShadowCubeApp() 0.2f, // - light_ambient_factor 5.f // - light_specular_factor }) + , m_shadow_pass(false, "Shadow Render Pass") + , m_final_pass(true, "Final Render Pass") { m_view_camera.SetOrientation({ { 15.0f, 22.5f, -15.0f }, { 0.0f, 7.5f, 0.0f }, { 0.0f, 1.0f, 0.0f } }); m_light_camera.SetOrientation({ { 0.0f, 25.0f, -25.0f }, { 0.0f, 7.5f, 0.0f }, { 0.0f, 1.0f, 0.0f } }); m_light_camera.SetProjection(gfx::Camera::Projection::Orthogonal); - m_light_camera.SetParamters({ -300, 300.f, 90.f }); + m_light_camera.SetParameters({ -300, 300.f, 90.f }); m_light_camera.Resize(80, 80); m_animations.push_back( @@ -94,119 +111,126 @@ void ShadowCubeApp::Init() { GraphicsApp::Init(); - assert(m_sp_context); - const gfx::Context::Settings& context_settings = m_sp_context->GetSettings(); + const gfx::RenderContext::Settings& context_settings = m_sp_context->GetSettings(); + m_view_camera.Resize(static_cast(context_settings.frame_size.width), + static_cast(context_settings.frame_size.height)); + + const gfx::Mesh::VertexLayout mesh_layout(Vertex::layout); + const gfx::CubeMesh cube_mesh(mesh_layout, 1.f, 1.f, 1.f); + const gfx::QuadMesh floor_mesh(mesh_layout, 7.f, 7.f, 0.f, 0, gfx::QuadMesh::FaceType::XZ); // Load textures, vertex and index buffers for cube and floor meshes - m_sp_cube_buffers = std::make_unique(*m_sp_context, m_cube_mesh, "Cube"); + m_sp_cube_buffers = std::make_unique(*m_sp_context, cube_mesh, "Cube"); m_sp_cube_buffers->SetTexture(m_image_loader.LoadImageToTexture2D(*m_sp_context, "Textures/MethaneBubbles.jpg", true)); - m_sp_floor_buffers = std::make_unique(*m_sp_context, m_floor_mesh, "Floor"); + m_sp_floor_buffers = std::make_unique(*m_sp_context, floor_mesh, "Floor"); m_sp_floor_buffers->SetTexture(m_image_loader.LoadImageToTexture2D(*m_sp_context, "Textures/MarbleWhite.jpg", true)); - m_view_camera.Resize(static_cast(context_settings.frame_size.width), - static_cast(context_settings.frame_size.height)); - const Data::Size constants_data_size = gfx::Buffer::GetAlignedBufferSize(static_cast(sizeof(Constants))); const Data::Size scene_uniforms_data_size = gfx::Buffer::GetAlignedBufferSize(static_cast(sizeof(SceneUniforms))); - const Data::Size cube_uniforms_data_size = gfx::Buffer::GetAlignedBufferSize(static_cast(sizeof(MeshUniforms))); - const Data::Size floor_uniforms_data_size = gfx::Buffer::GetAlignedBufferSize(static_cast(sizeof(MeshUniforms))); + const Data::Size mesh_uniforms_data_size = gfx::Buffer::GetAlignedBufferSize(static_cast(sizeof(MeshUniforms))); // Create constants buffer for frame rendering m_sp_const_buffer = gfx::Buffer::CreateConstantBuffer(*m_sp_context, constants_data_size); m_sp_const_buffer->SetName("Constants Buffer"); m_sp_const_buffer->SetData({ { reinterpret_cast(&m_scene_constants), sizeof(m_scene_constants) } }); - // Create sampler for image texture - m_sp_texture_sampler = gfx::Sampler::Create(*m_sp_context, { - { gfx::Sampler::Filter::MinMag::Linear }, // Bilinear filtering - { gfx::Sampler::Address::Mode::ClampToZero } - }); + // Create sampler for cube and floor textures sampling + m_sp_texture_sampler = gfx::Sampler::Create(*m_sp_context, + gfx::Sampler::Settings + { + gfx::Sampler::Filter { gfx::Sampler::Filter::MinMag::Linear }, + gfx::Sampler::Address { gfx::Sampler::Address::Mode::ClampToEdge } + } + ); m_sp_texture_sampler->SetName("Texture Sampler"); - // Create sampler for shadow-map - m_sp_shadow_sampler = gfx::Sampler::Create(*m_sp_context, { - { gfx::Sampler::Filter::MinMag::Linear }, // Bilinear filtering - { gfx::Sampler::Address::Mode::ClampToEdge } - }); + // Create sampler for shadow-map texture + m_sp_shadow_sampler = gfx::Sampler::Create(*m_sp_context, + gfx::Sampler::Settings + { + gfx::Sampler::Filter { gfx::Sampler::Filter::MinMag::Linear }, + gfx::Sampler::Address { gfx::Sampler::Address::Mode::ClampToEdge } + } + ); m_sp_shadow_sampler->SetName("Shadow Map Sampler"); // ========= Final Pass objects ========= - // Create final-pass shading program with texturing - gfx::Shader::MacroDefinitions textured_shadows_definitions = { { "ENABLE_SHADOWS", "" }, { "ENABLE_TEXTURING", "" } }; - m_final_pass.sp_program = gfx::Program::Create(*m_sp_context, { + const gfx::Shader::EntryFunction vs_main = { "ShadowCube", "CubeVS" }; + const gfx::Shader::EntryFunction ps_main = { "ShadowCube", "CubePS" }; + const gfx::Shader::MacroDefinitions textured_shadows_definitions = { { "ENABLE_SHADOWS", "" }, { "ENABLE_TEXTURING", "" } }; + + // Create final pass rendering state with program + gfx::RenderState::Settings final_state_settings; + final_state_settings.sp_program = gfx::Program::Create(*m_sp_context, + gfx::Program::Settings { - gfx::Shader::CreateVertex(*m_sp_context, { Data::ShaderProvider::Get(), g_vs_main, textured_shadows_definitions }), - gfx::Shader::CreatePixel(*m_sp_context, { Data::ShaderProvider::Get(), g_ps_main, textured_shadows_definitions }), - }, - { // input_buffer_layouts - { // Signle vertex buffer with interleaved data: + gfx::Program::Shaders + { + gfx::Shader::CreateVertex(*m_sp_context, { Data::ShaderProvider::Get(), vs_main, textured_shadows_definitions }), + gfx::Shader::CreatePixel(*m_sp_context, { Data::ShaderProvider::Get(), ps_main, textured_shadows_definitions }), + }, + gfx::Program::InputBufferLayouts + { + gfx::Program::InputBufferLayout { - { "input_position", "POSITION" }, - { "input_normal", "NORMAL" }, - { "input_texcoord", "TEXCOORD" }, + gfx::Program::InputBufferLayout::ArgumentSemantics { cube_mesh.GetVertexLayout().GetSemantics() } } - } - }, - { // constant_argument_names - "g_constants", "g_texture_sampler", "g_shadow_sampler" - }, - { // addressable_argument_names - }, - { // render_target_pixel_formats - context_settings.color_format - }, - context_settings.depth_stencil_format - }); - m_final_pass.sp_program->SetName("Textured, Shadows & Lighting"); - - // Create state for final pass rendering - gfx::RenderState::Settings final_state_settings; - final_state_settings.sp_program = m_final_pass.sp_program; + }, + gfx::Program::ArgumentDescriptions + { + { { gfx::Shader::Type::Vertex, "g_mesh_uniforms" }, gfx::Program::Argument::Modifiers::None }, + { { gfx::Shader::Type::Pixel, "g_scene_uniforms" }, gfx::Program::Argument::Modifiers::None }, + { { gfx::Shader::Type::Pixel, "g_constants" }, gfx::Program::Argument::Modifiers::Constant }, + { { gfx::Shader::Type::Pixel, "g_shadow_map" }, gfx::Program::Argument::Modifiers::None }, + { { gfx::Shader::Type::Pixel, "g_shadow_sampler" }, gfx::Program::Argument::Modifiers::Constant }, + { { gfx::Shader::Type::Pixel, "g_texture" }, gfx::Program::Argument::Modifiers::None }, + { { gfx::Shader::Type::Pixel, "g_texture_sampler"}, gfx::Program::Argument::Modifiers::Constant }, + }, + gfx::PixelFormats + { + context_settings.color_format + }, + context_settings.depth_stencil_format + } + ); + final_state_settings.sp_program->SetName("Textured, Shadows & Lighting"); final_state_settings.viewports = { gfx::GetFrameViewport(context_settings.frame_size) }; final_state_settings.scissor_rects = { gfx::GetFrameScissorRect(context_settings.frame_size) }; final_state_settings.depth.enabled = true; m_final_pass.sp_state = gfx::RenderState::Create(*m_sp_context, final_state_settings); m_final_pass.sp_state->SetName("Final pass render state"); - - m_final_pass.command_group_name = "Final Render Pass"; - m_final_pass.is_final_pass = true; // ========= Shadow Pass objects ========= - // Shadow texture settings - gfx::Texture::Settings shadow_texture_settings = gfx::Texture::Settings::DepthStencilBuffer(g_shadow_map_size, context_settings.depth_stencil_format, gfx::Texture::Usage::RenderTarget | gfx::Texture::Usage::ShaderRead); - - // Create shadow-pass program for geometry-only rendering to depth texture - gfx::Shader::MacroDefinitions textured_definitions = { { "ENABLE_TEXTURING", "" } }; - m_shadow_pass.sp_program = gfx::Program::Create(*m_sp_context, { - { - gfx::Shader::CreateVertex(*m_sp_context, { Data::ShaderProvider::Get(), g_vs_main, textured_definitions }), - }, - m_final_pass.sp_program->GetSettings().input_buffer_layouts, - { - "g_constants", "g_shadow_sampler" - }, - { // addressable_argument_names - }, - { // no color attachments, rendering to depth texture - }, - shadow_texture_settings.pixel_format - }); - m_shadow_pass.sp_program->SetName("Vertex Only: Textured, Lighting"); + gfx::Texture::Settings shadow_texture_settings = gfx::Texture::Settings::DepthStencilBuffer(g_shadow_map_size, context_settings.depth_stencil_format, gfx::Texture::Usage::RenderTarget | gfx::Texture::Usage::ShaderRead); + gfx::Shader::MacroDefinitions textured_definitions = { { "ENABLE_TEXTURING", "" } }; - // Create state for shadow map rendering + // Create shadow-pass rendering state with program gfx::RenderState::Settings shadow_state_settings; - shadow_state_settings.sp_program = m_shadow_pass.sp_program; + shadow_state_settings.sp_program = gfx::Program::Create(*m_sp_context, + gfx::Program::Settings + { + gfx::Program::Shaders + { + gfx::Shader::CreateVertex(*m_sp_context, { Data::ShaderProvider::Get(), vs_main, textured_definitions }), + }, + final_state_settings.sp_program->GetSettings().input_buffer_layouts, + gfx::Program::ArgumentDescriptions + { + { { gfx::Shader::Type::All, "g_mesh_uniforms" }, gfx::Program::Argument::Modifiers::None }, + }, + gfx::PixelFormats { /* no color attachments, rendering to depth texture */ }, + shadow_texture_settings.pixel_format + } + ); + shadow_state_settings.sp_program->SetName("Vertex Only: Textured, Lighting"); shadow_state_settings.viewports = { gfx::GetFrameViewport(g_shadow_map_size) }; shadow_state_settings.scissor_rects = { gfx::GetFrameScissorRect(g_shadow_map_size) }; shadow_state_settings.depth.enabled = true; m_shadow_pass.sp_state = gfx::RenderState::Create(*m_sp_context, shadow_state_settings); m_shadow_pass.sp_state->SetName("Shadow-map render state"); - - m_shadow_pass.command_group_name = "Shadow Render Pass"; - m_shadow_pass.is_final_pass = false; // ========= Per-Frame Data ========= for(ShadowCubeFrame& frame : m_frames) @@ -218,11 +242,11 @@ void ShadowCubeApp::Init() // ========= Shadow Pass data ========= // Create uniforms buffer for Cube rendering in Shadow pass - frame.shadow_pass.cube.sp_uniforms_buffer = gfx::Buffer::CreateConstantBuffer(*m_sp_context, cube_uniforms_data_size); + frame.shadow_pass.cube.sp_uniforms_buffer = gfx::Buffer::CreateConstantBuffer(*m_sp_context, mesh_uniforms_data_size); frame.shadow_pass.cube.sp_uniforms_buffer->SetName(IndexedName("Cube Uniforms Buffer for Shadow Pass", frame.index)); // Create uniforms buffer for Floor rendering in Shadow pass - frame.shadow_pass.floor.sp_uniforms_buffer = gfx::Buffer::CreateConstantBuffer(*m_sp_context, floor_uniforms_data_size); + frame.shadow_pass.floor.sp_uniforms_buffer = gfx::Buffer::CreateConstantBuffer(*m_sp_context, mesh_uniforms_data_size); frame.shadow_pass.floor.sp_uniforms_buffer->SetName(IndexedName("Floor Uniforms Buffer for Shadow Pass", frame.index)); // Create depth texture for shadow map rendering @@ -251,23 +275,23 @@ void ShadowCubeApp::Init() frame.shadow_pass.sp_cmd_list->SetName(IndexedName("Shadow-Map Rendering", frame.index)); // Shadow-pass resource bindings for cube rendering - frame.shadow_pass.cube.sp_resource_bindings = gfx::Program::ResourceBindings::Create(m_shadow_pass.sp_program, { + frame.shadow_pass.cube.sp_program_bindings = gfx::ProgramBindings::Create(shadow_state_settings.sp_program, { { { gfx::Shader::Type::All, "g_mesh_uniforms" }, { { frame.shadow_pass.cube.sp_uniforms_buffer } } }, }); // Shadow-pass resource bindings for floor rendering - frame.shadow_pass.floor.sp_resource_bindings = gfx::Program::ResourceBindings::Create(m_shadow_pass.sp_program, { + frame.shadow_pass.floor.sp_program_bindings = gfx::ProgramBindings::Create(shadow_state_settings.sp_program, { { { gfx::Shader::Type::All, "g_mesh_uniforms" }, { { frame.shadow_pass.floor.sp_uniforms_buffer } } }, }); // ========= Final Pass data ========= // Create uniforms buffer for Cube rendering in Final pass - frame.final_pass.cube.sp_uniforms_buffer = gfx::Buffer::CreateConstantBuffer(*m_sp_context, cube_uniforms_data_size); + frame.final_pass.cube.sp_uniforms_buffer = gfx::Buffer::CreateConstantBuffer(*m_sp_context, mesh_uniforms_data_size); frame.final_pass.cube.sp_uniforms_buffer->SetName(IndexedName("Cube Uniforms Buffer for Final Pass", frame.index)); // Create uniforms buffer for Floor rendering in Final pass - frame.final_pass.floor.sp_uniforms_buffer = gfx::Buffer::CreateConstantBuffer(*m_sp_context, floor_uniforms_data_size); + frame.final_pass.floor.sp_uniforms_buffer = gfx::Buffer::CreateConstantBuffer(*m_sp_context, mesh_uniforms_data_size); frame.final_pass.floor.sp_uniforms_buffer->SetName(IndexedName("Floor Uniforms Buffer for Final Pass", frame.index)); // Bind final pass RT texture and pass to the frame buffer texture and final pass. @@ -279,20 +303,20 @@ void ShadowCubeApp::Init() frame.final_pass.sp_cmd_list->SetName(IndexedName("Final Scene Rendering", frame.index)); // Final-pass resource bindings for cube rendering - frame.final_pass.cube.sp_resource_bindings = gfx::Program::ResourceBindings::Create(m_final_pass.sp_program, { + frame.final_pass.cube.sp_program_bindings = gfx::ProgramBindings::Create(final_state_settings.sp_program, { { { gfx::Shader::Type::Vertex, "g_mesh_uniforms" }, { { frame.final_pass.cube.sp_uniforms_buffer } } }, { { gfx::Shader::Type::Pixel, "g_scene_uniforms" }, { { frame.sp_scene_uniforms_buffer } } }, { { gfx::Shader::Type::Pixel, "g_constants" }, { { m_sp_const_buffer } } }, { { gfx::Shader::Type::Pixel, "g_shadow_map" }, { { frame.shadow_pass.sp_rt_texture } } }, { { gfx::Shader::Type::Pixel, "g_shadow_sampler" }, { { m_sp_shadow_sampler } } }, - { { gfx::Shader::Type::Pixel, "g_texture" }, { { m_sp_cube_buffers->GetSubsetTexturePtr() } } }, + { { gfx::Shader::Type::Pixel, "g_texture" }, { { m_sp_cube_buffers->GetTexturePtr() } } }, { { gfx::Shader::Type::Pixel, "g_texture_sampler"}, { { m_sp_texture_sampler } } }, }); // Final-pass resource bindings for floor rendering - patched a copy of cube bindings - frame.final_pass.floor.sp_resource_bindings = gfx::Program::ResourceBindings::CreateCopy(*frame.final_pass.cube.sp_resource_bindings, { + frame.final_pass.floor.sp_program_bindings = gfx::ProgramBindings::CreateCopy(*frame.final_pass.cube.sp_program_bindings, { { { gfx::Shader::Type::Vertex, "g_mesh_uniforms" }, { { frame.final_pass.floor.sp_uniforms_buffer } } }, - { { gfx::Shader::Type::Pixel, "g_texture" }, { { m_sp_floor_buffers->GetSubsetTexturePtr() } } }, + { { gfx::Shader::Type::Pixel, "g_texture" }, { { m_sp_floor_buffers->GetTexturePtr() } } }, }); } @@ -304,7 +328,6 @@ void ShadowCubeApp::Init() void ShadowCubeApp::RenderPass::Release() { - sp_program.reset(); sp_state.reset(); } @@ -323,7 +346,6 @@ bool ShadowCubeApp::Resize(const gfx::FrameSize& frame_size, bool is_minimized) return false; // Update viewports and scissor rects state - assert(m_final_pass.sp_state); m_final_pass.sp_state->SetViewports({ gfx::GetFrameViewport(frame_size) }); m_final_pass.sp_state->SetScissorRects({ gfx::GetFrameScissorRect(frame_size) }); @@ -347,7 +369,7 @@ bool ShadowCubeApp::Update() m_light_camera.GetViewProjMatrices(light_view_matrix, light_proj_matrix); // Prepare shadow transform matrix - static const gfx::Matrix44f shadow_transform_matrix = ([]() -> gfx::Matrix44f + static const gfx::Matrix44f s_shadow_transform_matrix = ([]() -> gfx::Matrix44f { gfx::Matrix44f shadow_scale_matrix, shadow_translate_matrix; cml::matrix_scale(shadow_scale_matrix, 0.5f, -0.5f, 1.f); @@ -361,30 +383,30 @@ bool ShadowCubeApp::Update() // Cube model matrix gfx::Matrix44f cube_model_matrix; - cml::matrix_translation(cube_model_matrix, gfx::Vector3f(0.f, m_cube_mesh.GetHeight() / 2.f, 0.f)); + cml::matrix_translation(cube_model_matrix, gfx::Vector3f(0.f, 0.5f, 0.f)); // move up by half of cube model height cube_model_matrix = cube_model_matrix * scale_matrix; // Update Cube uniforms m_sp_cube_buffers->SetFinalPassUniforms(MeshUniforms{ cube_model_matrix, - cube_model_matrix* scene_view_matrix * scene_proj_matrix, - cube_model_matrix* light_view_matrix * light_proj_matrix * shadow_transform_matrix + cube_model_matrix * scene_view_matrix * scene_proj_matrix, + cube_model_matrix * light_view_matrix * light_proj_matrix * s_shadow_transform_matrix }); m_sp_cube_buffers->SetShadowPassUniforms(MeshUniforms{ cube_model_matrix, - cube_model_matrix* light_view_matrix * light_proj_matrix, + cube_model_matrix * light_view_matrix * light_proj_matrix, gfx::Matrix44f() }); // Update Floor uniforms m_sp_floor_buffers->SetFinalPassUniforms(MeshUniforms{ scale_matrix, - scale_matrix* scene_view_matrix * scene_proj_matrix, - scale_matrix* light_view_matrix * light_proj_matrix * shadow_transform_matrix + scale_matrix * scene_view_matrix * scene_proj_matrix, + scale_matrix * light_view_matrix * light_proj_matrix * s_shadow_transform_matrix }); m_sp_floor_buffers->SetShadowPassUniforms(MeshUniforms{ scale_matrix, - scale_matrix* light_view_matrix * light_proj_matrix, + scale_matrix * light_view_matrix * light_proj_matrix, gfx::Matrix44f() }); @@ -394,7 +416,6 @@ bool ShadowCubeApp::Update() bool ShadowCubeApp::Render() { // Render only when context is ready - assert(!!m_sp_context); if (!m_sp_context->ReadyToRender() || !GraphicsApp::Render()) return false; @@ -403,11 +424,12 @@ bool ShadowCubeApp::Render() ShadowCubeFrame& frame = GetCurrentFrame(); // Upload uniform buffers to GPU + const Data::Size mesh_uniforms_buffer_size = sizeof(MeshUniforms); frame.sp_scene_uniforms_buffer->SetData({ {reinterpret_cast(&m_scene_uniforms), sizeof(SceneUniforms) } }); - frame.shadow_pass.floor.sp_uniforms_buffer->SetData({ { reinterpret_cast(&m_sp_floor_buffers->GetShadowPassUniforms()), sizeof(MeshUniforms) } }); - frame.shadow_pass.cube.sp_uniforms_buffer->SetData({ { reinterpret_cast(&m_sp_cube_buffers->GetShadowPassUniforms()), sizeof(MeshUniforms) } }); - frame.final_pass.floor.sp_uniforms_buffer->SetData({ { reinterpret_cast(&m_sp_floor_buffers->GetFinalPassUniforms()), sizeof(MeshUniforms) } }); - frame.final_pass.cube.sp_uniforms_buffer->SetData({ { reinterpret_cast(&m_sp_cube_buffers->GetFinalPassUniforms()), sizeof(MeshUniforms) } }); + frame.shadow_pass.floor.sp_uniforms_buffer->SetData({ { reinterpret_cast(&m_sp_floor_buffers->GetShadowPassUniforms()), mesh_uniforms_buffer_size } }); + frame.shadow_pass.cube.sp_uniforms_buffer->SetData({ { reinterpret_cast(&m_sp_cube_buffers->GetShadowPassUniforms()), mesh_uniforms_buffer_size } }); + frame.final_pass.floor.sp_uniforms_buffer->SetData({ { reinterpret_cast(&m_sp_floor_buffers->GetFinalPassUniforms()), mesh_uniforms_buffer_size } }); + frame.final_pass.cube.sp_uniforms_buffer->SetData({ { reinterpret_cast(&m_sp_cube_buffers->GetFinalPassUniforms()), mesh_uniforms_buffer_size } }); // Record commands for shadow & final render passes RenderScene(m_shadow_pass, frame.shadow_pass, *frame.shadow_pass.sp_rt_texture); @@ -425,22 +447,14 @@ bool ShadowCubeApp::Render() void ShadowCubeApp::RenderScene(const RenderPass &render_pass, ShadowCubeFrame::PassResources &render_pass_resources, gfx::Texture &shadow_texture) { - assert(!!render_pass_resources.sp_cmd_list); gfx::RenderCommandList& cmd_list = *render_pass_resources.sp_cmd_list; // Reset command list with initial rendering state - assert(!!render_pass.sp_state); cmd_list.Reset(render_pass.sp_state, render_pass.command_group_name); - // Cube drawing - assert(!!render_pass_resources.cube.sp_resource_bindings); - assert(!!m_sp_cube_buffers); - m_sp_cube_buffers->Draw(cmd_list, *render_pass_resources.cube.sp_resource_bindings); - - // Floor drawing - assert(!!render_pass_resources.floor.sp_resource_bindings); - assert(!!m_sp_floor_buffers); - m_sp_floor_buffers->Draw(cmd_list, *render_pass_resources.floor.sp_resource_bindings); + // Draw scene with cube and floor + m_sp_cube_buffers->Draw(cmd_list, *render_pass_resources.cube.sp_program_bindings); + m_sp_floor_buffers->Draw(cmd_list, *render_pass_resources.floor.sp_program_bindings); if (render_pass.is_final_pass) { @@ -448,7 +462,7 @@ void ShadowCubeApp::RenderScene(const RenderPass &render_pass, ShadowCubeFrame:: } // Commit command list with present flag in case of final render pass - cmd_list.Commit(render_pass.is_final_pass); + cmd_list.Commit(); } void ShadowCubeApp::OnContextReleased() diff --git a/Apps/Tutorials/03-ShadowCube/ShadowCubeApp.h b/Apps/Tutorials/03-ShadowCube/ShadowCubeApp.h index c61aba385..6baf272b0 100644 --- a/Apps/Tutorials/03-ShadowCube/ShadowCubeApp.h +++ b/Apps/Tutorials/03-ShadowCube/ShadowCubeApp.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -37,20 +37,20 @@ struct ShadowCubeFrame final : gfx::AppFrame { struct MeshResources { - gfx::Buffer::Ptr sp_uniforms_buffer; - gfx::Program::ResourceBindings::Ptr sp_resource_bindings; + Ptr sp_uniforms_buffer; + Ptr sp_program_bindings; }; MeshResources cube; MeshResources floor; - gfx::Texture::Ptr sp_rt_texture; - gfx::RenderPass::Ptr sp_pass; - gfx::RenderCommandList::Ptr sp_cmd_list; + Ptr sp_rt_texture; + Ptr sp_pass; + Ptr sp_cmd_list; }; PassResources shadow_pass; PassResources final_pass; - gfx::Buffer::Ptr sp_scene_uniforms_buffer; + Ptr sp_scene_uniforms_buffer; using gfx::AppFrame::AppFrame; }; @@ -62,30 +62,16 @@ class ShadowCubeApp final : public GraphicsApp ShadowCubeApp(); ~ShadowCubeApp() override; - // NativeApp + // GraphicsApp overrides void Init() override; bool Resize(const gfx::FrameSize& frame_size, bool is_minimized) override; bool Update() override; bool Render() override; - // Context::Callback interface + // Context::Callback override void OnContextReleased() override; private: - struct Vertex - { - gfx::Mesh::Position position; - gfx::Mesh::Normal normal; - gfx::Mesh::TexCoord texcoord; - - using FieldsArray = std::array; - static constexpr const FieldsArray layout = { - gfx::Mesh::VertexField::Position, - gfx::Mesh::VertexField::Normal, - gfx::Mesh::VertexField::TexCoord, - }; - }; - struct SHADER_STRUCT_ALIGN Constants { SHADER_FIELD_ALIGN gfx::Color4f light_color; @@ -111,11 +97,10 @@ class ShadowCubeApp final : public GraphicsApp class TexturedMeshBuffers : public TexturedMeshBuffersBase { public: - using Ptr = std::unique_ptr; using TexturedMeshBuffersBase::TexturedMeshBuffersBase; - const MeshUniforms& GetShadowPassUniforms() const { return m_shadow_pass_uniforms; } - void SetShadowPassUniforms(const MeshUniforms& uniforms) { m_shadow_pass_uniforms = uniforms; } + const MeshUniforms& GetShadowPassUniforms() const { return m_shadow_pass_uniforms; } + void SetShadowPassUniforms(const MeshUniforms& uniforms) { m_shadow_pass_uniforms = uniforms; } private: MeshUniforms m_shadow_pass_uniforms = {}; @@ -123,31 +108,31 @@ class ShadowCubeApp final : public GraphicsApp struct RenderPass { - gfx::Program::Ptr sp_program; - gfx::RenderState::Ptr sp_state; - std::string command_group_name; - bool is_final_pass = false; + RenderPass(bool is_final_pass, std::string command_group_name) + : is_final_pass(is_final_pass) + , command_group_name(std::move(command_group_name)) + { } + + const bool is_final_pass; + const std::string command_group_name; + Ptr sp_state; void Release(); }; - void RenderScene(const RenderPass &render_pass, ShadowCubeFrame::PassResources &render_pass_resources, - gfx::Texture &shadow_texture); + void RenderScene(const RenderPass &render_pass, ShadowCubeFrame::PassResources &render_pass_resources, gfx::Texture &shadow_texture); - const gfx::BoxMesh m_cube_mesh; - const gfx::RectMesh m_floor_mesh; const float m_scene_scale; const Constants m_scene_constants; - + SceneUniforms m_scene_uniforms = { }; gfx::Camera m_view_camera; gfx::Camera m_light_camera; - gfx::Buffer::Ptr m_sp_const_buffer; - gfx::Sampler::Ptr m_sp_texture_sampler; - gfx::Sampler::Ptr m_sp_shadow_sampler; - SceneUniforms m_scene_uniforms = { }; - TexturedMeshBuffers::Ptr m_sp_cube_buffers; - TexturedMeshBuffers::Ptr m_sp_floor_buffers; + Ptr m_sp_const_buffer; + Ptr m_sp_texture_sampler; + Ptr m_sp_shadow_sampler; + Ptr m_sp_cube_buffers; + Ptr m_sp_floor_buffers; RenderPass m_shadow_pass; RenderPass m_final_pass; }; diff --git a/Build/Posix/AzureBuild.yml b/Build/Posix/AzureBuild.yml index 036534c87..19c605d7b 100644 --- a/Build/Posix/AzureBuild.yml +++ b/Build/Posix/AzureBuild.yml @@ -27,6 +27,12 @@ steps: workingDirectory: '$(installDir)/Tests' displayName: 'Run all unit-tests from install directory' + - script: | + cp $(rootDir)/README.md README.md + echo Build number: $(Build.BuildNumber), git branch: $(Build.SourceBranchName), commit id: $(Build.SourceVersion) >Build.txt + workingDirectory: '$(installDir)' + displayName: 'Copy ReadMe and write build information' + - task: CopyFiles@2 displayName: 'Copy install artifacts for $(platform) $(configuration)' inputs: diff --git a/Build/Posix/Build.sh b/Build/Posix/Build.sh index fd9f19f45..08de58c3f 100755 --- a/Build/Posix/Build.sh +++ b/Build/Posix/Build.sh @@ -19,7 +19,7 @@ case "${UNAME_OUT}" in *) echo "Unsupported operating system!" 1>&2 && exit 1;; esac -CONFIG_TYPE=Release +BUILD_TYPE=Release BUILD_VERSION=0.2 SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd ) @@ -31,7 +31,8 @@ CMAKE_FLAGS="-DMETHANE_VERSION=$BUILD_VERSION \ -DMETHANE_ITT_INSTRUMENTATION_ENABLED:BOOL=ON \ -DMETHANE_SCOPE_TIMERS_ENABLED:BOOL=OFF \ -DMETHANE_RUN_TESTS_DURING_BUILD:BOOL=OFF \ - -DMETHANE_USE_OPEN_IMAGE_IO:BOOL=OFF" + -DMETHANE_USE_OPEN_IMAGE_IO:BOOL=OFF \ + -DMETHANE_COMMAND_EXECUTION_LOGGING:BOOL=OFF" if [ "$IS_ANALYZE_BUILD" == true ]; then @@ -42,14 +43,14 @@ if [ "$IS_ANALYZE_BUILD" == true ]; then SONAR_SCANNER_EXE=$SONAR_SCANNER_DIR/bin/sonar-scanner echo ========================================================= - echo Code analysis for build Methane $CONFIG_TYPE + echo Code analysis for build Methane $BUILD_TYPE echo ========================================================= echo \* Build in: $BUILD_DIR echo ========================================================= else BUILD_DIR=$OUTPUT_DIR/Build echo ========================================================= - echo Clean build and install Methane $CONFIG_TYPE + echo Clean build and install Methane $BUILD_TYPE echo ========================================================= echo \* Build in: $BUILD_DIR echo \* Install to: $INSTALL_DIR @@ -89,8 +90,8 @@ if [ "$IS_ANALYZE_BUILD" == true ]; then else echo Building with $CMAKE_GENERATOR... cmake -H"$SOURCE_DIR" -B"$BUILD_DIR" -G "$CMAKE_GENERATOR" -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" $CMAKE_FLAGS - cmake --build "$BUILD_DIR" --config $CONFIG_TYPE --target install + cmake --build "$BUILD_DIR" --config $BUILD_TYPE --target install echo Running unit-tests... - cmake -E chdir "$BUILD_DIR" ctest --build-config $CONFIG_TYPE --output-on-failure + cmake -E chdir "$BUILD_DIR" ctest --build-config $BUILD_TYPE --output-on-failure fi \ No newline at end of file diff --git a/Build/Windows/AzureBuild.yml b/Build/Windows/AzureBuild.yml index 5494ce33b..ad80d76a7 100644 --- a/Build/Windows/AzureBuild.yml +++ b/Build/Windows/AzureBuild.yml @@ -4,11 +4,14 @@ steps: - script: | - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\$(vcVarsBatFile)" mkdir $(buildDir) - cd $(buildDir) - cmake -G $(generatorName) -DCMAKE_INSTALL_PREFIX:PATH=$(buildInstallDir) $(cmakeFlags) $(rootDir) + displayName: 'Make build directories for $(platform) $(configuration)' + + - task: CMake@1 displayName: 'Generate with $(generatorName) for $(platform) $(configuration)' + inputs: + workingDirectory: $(buildDir) + cmakeArgs: '-G $(generatorName) -DCMAKE_INSTALL_PREFIX:PATH=$(buildInstallDir) $(cmakeFlags) $(rootDir)' - task: CMake@1 displayName: 'Build with $(generatorName) for $(platform) $(configuration)' @@ -21,6 +24,12 @@ steps: workingDirectory: '$(installDir)\Tests' displayName: 'Run all unit-tests from install directory' + - script: | + copy $(rootDir)\README.md README.md + echo Build number: $(Build.BuildNumber), git branch: $(Build.SourceBranchName), commit id: $(Build.SourceVersion) >Build.txt + workingDirectory: '$(installDir)' + displayName: 'Copy ReadMe and write build information' + - task: CopyFiles@2 displayName: 'Copy install artifacts for $(platform) $(configuration)' inputs: diff --git a/Build/Windows/Build.bat b/Build/Windows/Build.bat index 5594b8afe..2c0a7a7e2 100644 --- a/Build/Windows/Build.bat +++ b/Build/Windows/Build.bat @@ -3,7 +3,8 @@ SETLOCAL ENABLEDELAYEDEXPANSION SET PLATFORM_TYPE=Win64 -SET CONFIG_TYPE=Release +SET ARCH_TYPE=x64 +SET BUILD_TYPE=Release SET BUILD_VERSION=0.2 SET CMAKE_FLAGS= ^ -DMETHANE_VERSION=%BUILD_VERSION% ^ @@ -11,18 +12,21 @@ SET CMAKE_FLAGS= ^ -DMETHANE_ITT_INSTRUMENTATION_ENABLED:BOOL=ON ^ -DMETHANE_SCOPE_TIMERS_ENABLED:BOOL=OFF ^ -DMETHANE_RUN_TESTS_DURING_BUILD:BOOL=OFF ^ - -DMETHANE_USE_OPEN_IMAGE_IO:BOOL=OFF + -DMETHANE_USE_OPEN_IMAGE_IO:BOOL=OFF ^ + -DMETHANE_COMMAND_EXECUTION_LOGGING:BOOL=OFF -SET CONFIG_DIR=%~dp0..\Output\VisualStudio\%PLATFORM_TYPE%-%CONFIG_TYPE% +SET CONFIG_DIR=%~dp0..\Output\VisualStudio\%PLATFORM_TYPE%-%BUILD_TYPE% SET INSTALL_DIR=%CONFIG_DIR%\Install SET SOURCE_DIR=%~dp0..\.. SET START_DIR=%cd% IF "%~1"=="--vs2019" ( SET CMAKE_GENERATOR=Visual Studio 16 2019 +SET CMAKE_FLAGS=-A %ARCH_TYPE% %CMAKE_FLAGS% ) ELSE ( IF "%~2"=="--vs2019" ( SET CMAKE_GENERATOR=Visual Studio 16 2019 +SET CMAKE_FLAGS=-A %ARCH_TYPE% %CMAKE_FLAGS% ) ELSE ( SET CMAKE_GENERATOR=Visual Studio 15 2017 %PLATFORM_TYPE% ) ) @@ -37,7 +41,7 @@ IF "%~1"=="--analyze" ( SET SONAR_SCANNER_MSBUILD_EXE=!SONAR_SCANNER_DIR!\SonarScanner.MSBuild.exe ECHO ========================================================= - ECHO Code analysis for build Methane %PLATFORM_TYPE% %CONFIG_TYPE% + ECHO Code analysis for build Methane %PLATFORM_TYPE% %BUILD_TYPE% ECHO ========================================================= ECHO * Build in: '!BUILD_DIR!' ECHO ========================================================= @@ -48,7 +52,7 @@ IF "%~1"=="--analyze" ( SET BUILD_DIR=%CONFIG_DIR%\Build ECHO ========================================================= - ECHO Clean build and install Methane %PLATFORM_TYPE% %CONFIG_TYPE% + ECHO Clean build and install Methane %PLATFORM_TYPE% %BUILD_TYPE% ECHO ========================================================= ECHO * Build in: '!BUILD_DIR!' ECHO * Install to: '%INSTALL_DIR%' @@ -83,7 +87,7 @@ IF %IS_ANALYZE_BUILD% EQU 1 ( CD "%BUILD_DIR%" "%SONAR_BUILD_WRAPPER_EXE%" --out-dir "%BUILD_DIR%"^ - cmake -G "%CMAKE_GENERATOR%" -DCMAKE_BUILD_TYPE=%BUILD_TYPE% %CMAKE_FLAGS% "%SOURCE_DIR%" + cmake -G "%CMAKE_GENERATOR%" %CMAKE_FLAGS% "%SOURCE_DIR%" IF %ERRORLEVEL% NEQ 0 GOTO ERROR CD "%SOURCE_DIR%" @@ -111,15 +115,15 @@ IF %IS_ANALYZE_BUILD% EQU 1 ( ECHO Building with %CMAKE_GENERATOR%... - cmake -G "%CMAKE_GENERATOR%" -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% %CMAKE_FLAGS% "%SOURCE_DIR%" + cmake -G "%CMAKE_GENERATOR%" -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% %CMAKE_FLAGS% "%SOURCE_DIR%" IF %ERRORLEVEL% NEQ 0 GOTO ERROR - cmake --build . --config %CONFIG_TYPE% --target install + cmake --build . --config %BUILD_TYPE% --target install IF %ERRORLEVEL% NEQ 0 GOTO ERROR ECHO Running tests... - ctest --build-config %CONFIG_TYPE% --output-on-failure + ctest --build-config %BUILD_TYPE% --output-on-failure IF %ERRORLEVEL% NEQ 0 GOTO ERROR ) diff --git a/CMake/MethaneApplications.cmake b/CMake/MethaneApplications.cmake index 24a42768b..5408e7efe 100644 --- a/CMake/MethaneApplications.cmake +++ b/CMake/MethaneApplications.cmake @@ -35,18 +35,22 @@ function(add_methane_application TARGET SOURCES RESOURCES_DIR INSTALL_DIR APP_NA if (WIN32) - # Configure Resoruce file - set(METHANE_APP_EXECUTABLE ${COMPONENT_OUTPUT_NAME}.exe) - set(METHANE_APP_MANIEFEST_FILE_PATH ${RESOURCES_DIR}/Configs/Windows/App.manifest) + # Configure Resource and Manifest files + set(METHANE_APP_MANIFEST_FILE_PATH ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/App.manifest) + set(METHANE_APP_RESOURCE_FILE_PATH ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/Resource.rc) + set(METHANE_APP_EXECUTABLE ${TARGET}.exe) set(METHANE_APP_ICON_FILE_PATH ${RESOURCES_DIR}/Icons/Windows/Methane.ico) - set(RESOURCE_FILE ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/Resource.rc) string(REPLACE "." "," METHANE_APP_SHORT_VERSION_CSV ${METHANE_APP_SHORT_VERSION}) string(REPLACE "." "," METHANE_APP_LONG_VERSION_CSV ${METHANE_APP_LONG_VERSION}) - configure_file(${RESOURCES_DIR}/Configs/Windows/Resource.rc.in ${RESOURCE_FILE}) + configure_file(${RESOURCES_DIR}/Configs/Windows/App.manifest.in ${METHANE_APP_MANIFEST_FILE_PATH}) + configure_file(${RESOURCES_DIR}/Configs/Windows/Resource.rc.in ${METHANE_APP_RESOURCE_FILE_PATH}) + + set(MANIFEST_FILE ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/Resource.rc) + configure_file(${RESOURCES_DIR}/Configs/Windows/Resource.rc.in ${METHANE_APP_RESOURCE_FILE_PATH}) add_executable(${TARGET} WIN32 ${SOURCES} - ${RESOURCE_FILE} + ${METHANE_APP_RESOURCE_FILE_PATH} ) install(TARGETS ${TARGET} @@ -62,7 +66,7 @@ function(add_methane_application TARGET SOURCES RESOURCES_DIR INSTALL_DIR APP_NA LINK_FLAGS "/MANIFEST:NO /ENTRY:mainCRTStartup" ) - source_group("Resources" FILES ${RESOURCE_FILE} ${ICON_FILE_PATH}) + source_group("Resources" FILES ${METHANE_APP_RESOURCE_FILE_PATH} ${ICON_FILE_PATH}) elseif(APPLE) @@ -121,11 +125,12 @@ function(add_methane_application TARGET SOURCES RESOURCES_DIR INSTALL_DIR APP_NA MethaneGraphicsKit ) - get_target_property(METHANE_PREREQUISITE_MODULES MethaneGraphicsKit PREREQUISITE_MODULES) - add_prerequisite_binaries(${TARGET} "${METHANE_PREREQUISITE_MODULES}") - target_include_directories(${TARGET} PUBLIC . ) + + get_target_property(METHANE_PREREQUISITE_MODULES MethaneGraphicsKit PREREQUISITE_MODULES) + add_prerequisite_binaries(${TARGET} "${METHANE_PREREQUISITE_MODULES}" ${INSTALL_DIR}) + endfunction() diff --git a/CMake/MethaneModules.cmake b/CMake/MethaneModules.cmake index 480855c3b..c62830ec0 100644 --- a/CMake/MethaneModules.cmake +++ b/CMake/MethaneModules.cmake @@ -21,6 +21,22 @@ Library module configuration functions *****************************************************************************]] +function(get_target_arch OUT_ARCH) + if(APPLE) + set(${OUT_ARCH} "" PARENT_SCOPE) + elseif(ARMEABI_V7A) + set(${OUT_ARCH} "arm" PARENT_SCOPE) + elseif(ARM64_V8A) + set(${OUT_ARCH} "arm64" PARENT_SCOPE) + elseif(${CMAKE_SIZEOF_VOID_P} STREQUAL "4") + set(${OUT_ARCH} "x86" PARENT_SCOPE) + elseif(${CMAKE_SIZEOF_VOID_P} STREQUAL "8") + set(${OUT_ARCH} "x64" PARENT_SCOPE) + else() + message(FATAL_ERROR "Unknown architecture") + endif() +endfunction() + function(get_platform_dir) if (WIN32) set(PLATFORM_DIR Windows PARENT_SCOPE) @@ -90,7 +106,7 @@ function(add_prerequisite_modules TO_TARGET FROM_TARGETS) ) endfunction() -function(add_prerequisite_binaries TO_TARGET FROM_TARGETS) +function(add_prerequisite_binaries TO_TARGET FROM_TARGETS INSTALL_DIR) foreach(FROM_TARGET ${FROM_TARGETS}) get_property(TARGET_PREREQUISITE_BINARIES_IS_SET TARGET ${FROM_TARGET} PROPERTY PREREQUISITE_BINARIES SET) if (TARGET_PREREQUISITE_BINARIES_IS_SET) @@ -108,6 +124,11 @@ function(add_prerequisite_binaries TO_TARGET FROM_TARGETS) COMMENT "Copying prerequisite binaries for application ${TO_TARGET}" COMMAND ${CMAKE_COMMAND} -E copy_if_different ${COPY_ALL_BINARIES} "$" ) + if (INSTALL_DIR) + install(FILES ${COPY_ALL_BINARIES} + DESTINATION ${INSTALL_DIR} + ) + endif() endif() if (COPY_ALL_RESOURCES) get_target_resources_dir(${TO_TARGET} RESOURCES_DIR) @@ -115,5 +136,10 @@ function(add_prerequisite_binaries TO_TARGET FROM_TARGETS) COMMENT "Copying prerequisite resources for application ${TO_TARGET}" COMMAND ${CMAKE_COMMAND} -E copy_if_different ${COPY_ALL_RESOURCES} "${RESOURCES_DIR}" ) + if (INSTALL_DIR AND NOT APPLE) + install(FILES ${COPY_ALL_RESOURCES} + DESTINATION ${INSTALL_DIR} + ) + endif() endif() endfunction() \ No newline at end of file diff --git a/CMake/MethaneShaders.cmake b/CMake/MethaneShaders.cmake index 730ab7b5e..a340b1593 100644 --- a/CMake/MethaneShaders.cmake +++ b/CMake/MethaneShaders.cmake @@ -18,7 +18,7 @@ limitations under the License. FILE: MethaneShaders.cmake Cross-platform HLSL shaders compilation and embedding into application resources -with transformation to Metal shaders using SPIR-V tools. +with transformation to Metal shaders using SPIRV tools. *****************************************************************************]] @@ -60,9 +60,9 @@ function(get_generated_shaders FOR_TARGET SHADERS_CONFIG SHADER_EXT SHADERS_GENE file(STRINGS ${SHADERS_CONFIG} CONFIG_STRINGS) foreach(KEY_VALUE_STRING ${CONFIG_STRINGS}) trim_spaces(${KEY_VALUE_STRING} KEY_VALUE_STRING) - split_by_first_delimiter(${KEY_VALUE_STRING} "=" SHADER_TYPE ENTRY_POINT_WITH_DEFINIES) + split_by_first_delimiter(${KEY_VALUE_STRING} "=" SHADER_TYPE ENTRY_POINT_WITH_DEFINES) - string(REGEX REPLACE ":| " "_" NEW_ENTRY_POINT ${ENTRY_POINT_WITH_DEFINIES}) + string(REGEX REPLACE ":| " "_" NEW_ENTRY_POINT ${ENTRY_POINT_WITH_DEFINES}) string(REPLACE "=" "" NEW_ENTRY_POINT "${NEW_ENTRY_POINT}") set(NEW_ENTRY_POINT "${SHADERS_NAME}_${NEW_ENTRY_POINT}") @@ -72,12 +72,15 @@ function(get_generated_shaders FOR_TARGET SHADERS_CONFIG SHADER_EXT SHADERS_GENE set(${SHADERS_GENERATED} ${_SHADERS_GENERATED} PARENT_SCOPE) endfunction() -function(generate_metal_shaders_from_hlsl FOR_TARGET SHADERS_HLSL OUT_SHADERS_METAL) +function(generate_metal_shaders_from_hlsl FOR_TARGET SHADERS_HLSL PROFILE_VER OUT_SHADERS_METAL) get_platform_dir() get_target_shaders_dir(${FOR_TARGET} TARGET_SHADERS_DIR) get_file_name(${SHADERS_HLSL} SHADERS_NAME) get_shaders_config(${SHADERS_HLSL} SHADERS_CONFIG) + set(DXC_BIN_DIR "${CMAKE_SOURCE_DIR}/Externals/DirectXCompiler/binaries/${PLATFORM_DIR}") + set(DXC_EXE "${DXC_BIN_DIR}/dxc") + set(SPIRV_BIN_DIR "${CMAKE_SOURCE_DIR}/Externals/SPIRV/binaries/${PLATFORM_DIR}") set(SPIRV_GEN_EXE "${SPIRV_BIN_DIR}/glslangValidator") set(SPIRV_CROSS_EXE "${SPIRV_BIN_DIR}/spirv-cross") @@ -85,8 +88,8 @@ function(generate_metal_shaders_from_hlsl FOR_TARGET SHADERS_HLSL OUT_SHADERS_ME file(STRINGS ${SHADERS_CONFIG} CONFIG_STRINGS) foreach(KEY_VALUE_STRING ${CONFIG_STRINGS}) trim_spaces(${KEY_VALUE_STRING} KEY_VALUE_STRING) - split_by_first_delimiter(${KEY_VALUE_STRING} "=" SHADER_TYPE ENTRY_POINT_WITH_DEFINIES) - split_by_first_delimiter(${ENTRY_POINT_WITH_DEFINIES} ":" OLD_ENTRY_POINT SHADER_DEFINITIONS) + split_by_first_delimiter(${KEY_VALUE_STRING} "=" SHADER_TYPE ENTRY_POINT_WITH_DEFINES) + split_by_first_delimiter(${ENTRY_POINT_WITH_DEFINES} ":" OLD_ENTRY_POINT SHADER_DEFINITIONS) set(NEW_ENTRY_POINT "${SHADERS_NAME}_${OLD_ENTRY_POINT}") string(REPLACE " " ";" SHADER_DEFINITIONS "${SHADER_DEFINITIONS}") @@ -102,16 +105,18 @@ function(generate_metal_shaders_from_hlsl FOR_TARGET SHADERS_HLSL OUT_SHADERS_ME set(SHADER_METAL_FILE "${NEW_ENTRY_POINT}.metal") set(SHADER_SPIRV_PATH "${TARGET_SHADERS_DIR}/${SHADER_SPIRV_FILE}") set(SHADER_METAL_PATH "${TARGET_SHADERS_DIR}/${SHADER_METAL_FILE}") - set(GENERATE_METAL_TARGET ${FOR_TARGET}_Generate_${SHADER_METAL_FILE}) + get_shader_profile(${SHADER_TYPE} ${PROFILE_VER} SHADER_PROFILE) + add_custom_target(${GENERATE_METAL_TARGET} COMMENT "Generating Metal shader source code from HLSL " ${NEW_ENTRY_POINT} " for application " ${TARGET} BYPRODUCTS "${SHADER_METAL_PATH}" DEPENDS ${SHADERS_HLSL} ${SHADERS_CONFIG} COMMAND ${CMAKE_COMMAND} -E make_directory "${TARGET_SHADERS_DIR}" - COMMAND ${SPIRV_GEN_EXE} --hlsl-iomap -S ${SHADER_TYPE} -e ${OLD_ENTRY_POINT} ${SHADER_DEFINITION_ARGUMENTS} -o "${SHADER_SPIRV_PATH}" -V -D "${SHADERS_HLSL}" - COMMAND ${SPIRV_CROSS_EXE} --msl --msl-version 020101 --rename-entry-point ${OLD_ENTRY_POINT} ${NEW_ENTRY_POINT} ${SHADER_TYPE} --output "${SHADER_METAL_PATH}" "${SHADER_SPIRV_PATH}" + COMMAND ${DXC_EXE} -spirv -T ${SHADER_PROFILE} -E ${OLD_ENTRY_POINT} ${SHADER_DEFINITION_ARGUMENTS} "${SHADERS_HLSL}" -Fo "${SHADER_SPIRV_PATH}" + #COMMAND ${SPIRV_GEN_EXE} --hlsl-iomap -S ${SHADER_TYPE} -e ${OLD_ENTRY_POINT} ${SHADER_DEFINITION_ARGUMENTS} -o "${SHADER_SPIRV_PATH}" -V -D "${SHADERS_HLSL}" + COMMAND ${SPIRV_CROSS_EXE} --msl --msl-version 020101 --msl-decoration-binding --rename-entry-point ${OLD_ENTRY_POINT} ${NEW_ENTRY_POINT} ${SHADER_TYPE} --output "${SHADER_METAL_PATH}" "${SHADER_SPIRV_PATH}" ) set_target_properties(${GENERATE_METAL_TARGET} @@ -119,6 +124,7 @@ function(generate_metal_shaders_from_hlsl FOR_TARGET SHADERS_HLSL OUT_SHADERS_ME FOLDER "Build/${FOR_TARGET}/Shaders" ) + add_dependencies(${GENERATE_METAL_TARGET} DirectXCompilerUnpack-build) add_dependencies(${GENERATE_METAL_TARGET} SPIRV-build) add_dependencies(${FOR_TARGET} ${GENERATE_METAL_TARGET}) @@ -132,7 +138,7 @@ function(compile_metal_shaders_to_library FOR_TARGET SDK METAL_SHADERS METAL_LIB get_target_shaders_dir(${FOR_TARGET} TARGET_SHADERS_DIR) if(METHANE_SHADERS_CODEVIEW_ENABLED OR CMAKE_BUILD_TYPE STREQUAL "Debug") - set(EXTRA_COMPILE_FLAGS -gcodeview) + set(EXTRA_COMPILE_FLAGS -gline-tables-only -MO) endif() foreach(SHADER_METAL_PATH ${METAL_SHADERS}) @@ -183,11 +189,13 @@ endfunction() function(compile_hlsl_shaders FOR_TARGET SHADERS_HLSL PROFILE_VER OUT_COMPILED_SHADER_BINS) get_platform_dir() + get_target_arch(WIN_ARCH) get_target_shaders_dir(${FOR_TARGET} TARGET_SHADERS_DIR) get_file_name(${SHADERS_HLSL} SHADERS_NAME) get_shaders_config(${SHADERS_HLSL} SHADERS_CONFIG) - set(SHADER_COMPILER_EXE "${WINDOWS_SDK_BIN_PATH}/fxc.exe") + set(SHADER_COMPILER_DIR "${CMAKE_SOURCE_DIR}/Externals/DirectXCompiler/binaries/${PLATFORM_DIR}-${WIN_ARCH}/bin") + set(SHADER_COMPILER_EXE "${SHADER_COMPILER_DIR}/dxc.exe") if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(EXTRA_COMPILE_FLAGS /Od) @@ -196,19 +204,19 @@ function(compile_hlsl_shaders FOR_TARGET SHADERS_HLSL PROFILE_VER OUT_COMPILED_S endif() if(METHANE_SHADERS_CODEVIEW_ENABLED OR CMAKE_BUILD_TYPE STREQUAL "Debug") - set(EXTRA_COMPILE_FLAGS ${EXTRA_COMPILE_FLAGS} /Zi) + set(EXTRA_COMPILE_FLAGS ${EXTRA_COMPILE_FLAGS} /Zi /Qembed_debug) endif() file(STRINGS ${SHADERS_CONFIG} CONFIG_STRINGS) foreach(KEY_VALUE_STRING ${CONFIG_STRINGS}) trim_spaces(${KEY_VALUE_STRING} KEY_VALUE_STRING) - split_by_first_delimiter(${KEY_VALUE_STRING} "=" SHADER_TYPE ENTRY_POINT_WITH_DEFINIES) - split_by_first_delimiter(${ENTRY_POINT_WITH_DEFINIES} ":" ORIG_ENTRY_POINT SHADER_DEFINITIONS) + split_by_first_delimiter(${KEY_VALUE_STRING} "=" SHADER_TYPE ENTRY_POINT_WITH_DEFINES) + split_by_first_delimiter(${ENTRY_POINT_WITH_DEFINES} ":" ORIG_ENTRY_POINT SHADER_DEFINITIONS) set(NEW_ENTRY_POINT ${ORIG_ENTRY_POINT}) string(REPLACE " " ";" SHADER_DEFINITIONS "${SHADER_DEFINITIONS}") - set(SHADER_DEFINITION_ARGUMENTS ) + set(SHADER_DEFINITION_ARGUMENTS) foreach(SHADER_DEFINITION ${SHADER_DEFINITIONS}) list(APPEND SHADER_DEFINITION_ARGUMENTS /D ${SHADER_DEFINITION}) string(REPLACE "=" "" SHADER_DEFINITION_NAME ${SHADER_DEFINITION}) @@ -227,10 +235,13 @@ function(compile_hlsl_shaders FOR_TARGET SHADERS_HLSL PROFILE_VER OUT_COMPILED_S COMMENT "Compiling HLSL shader from file " ${SHADERS_HLSL} " with profile " ${SHADER_PROFILE} " and macro-definition" ${SHADER_DEFINITIONS} "to OBJ file " ${SHADER_OBJ_FILE} BYPRODUCTS "${SHADER_OBJ_PATH}" DEPENDS ${SHADERS_HLSL} ${SHADERS_CONFIG} + WORKING_DIRECTORY "${SHADER_COMPILER_DIR}" COMMAND ${CMAKE_COMMAND} -E make_directory "${TARGET_SHADERS_DIR}" COMMAND ${SHADER_COMPILER_EXE} /T ${SHADER_PROFILE} /E ${ORIG_ENTRY_POINT} /Fo ${SHADER_OBJ_PATH} ${EXTRA_COMPILE_FLAGS} ${SHADER_DEFINITION_ARGUMENTS} ${SHADERS_HLSL} ) + add_dependencies(${COMPILE_SHADER_TARGET} DirectXCompilerUnpack-build) + set_target_properties(${COMPILE_SHADER_TARGET} PROPERTIES FOLDER "Build/${FOR_TARGET}/Shaders" @@ -242,7 +253,7 @@ function(compile_hlsl_shaders FOR_TARGET SHADERS_HLSL PROFILE_VER OUT_COMPILED_S set(${OUT_COMPILED_SHADER_BINS} ${_OUT_COMPILED_SHADER_BINS} PARENT_SCOPE) endfunction() -function(add_methane_shaders TARGET HLSL_SOURCES) +function(add_methane_shaders TARGET HLSL_SOURCES PROFILE_VER) set(RESOURCE_NAMESPACE ${TARGET}) @@ -266,7 +277,7 @@ function(add_methane_shaders TARGET HLSL_SOURCES) ) foreach(SHADERS_HLSL ${HLSL_SOURCES}) - compile_hlsl_shaders(${TARGET} ${SHADERS_HLSL} "5_1" OUT_COMPILED_SHADER_BINS) + compile_hlsl_shaders(${TARGET} ${SHADERS_HLSL} ${PROFILE_VER} OUT_COMPILED_SHADER_BINS) endforeach() target_sources(${TARGET} PRIVATE @@ -345,7 +356,7 @@ function(add_methane_shaders TARGET HLSL_SOURCES) foreach(SHADERS_HLSL ${HLSL_SOURCES}) set(SHADERS_METAL) # init with empty list get_metal_library(${TARGET} ${SHADERS_HLSL} METAL_LIBRARY) - generate_metal_shaders_from_hlsl(${TARGET} ${SHADERS_HLSL} SHADERS_METAL) + generate_metal_shaders_from_hlsl(${TARGET} ${SHADERS_HLSL} ${PROFILE_VER} SHADERS_METAL) compile_metal_shaders_to_library(${TARGET} "macosx" "${SHADERS_METAL}" "${METAL_LIBRARY}") endforeach() diff --git a/CMake/MethaneUtils.cmake b/CMake/MethaneUtils.cmake index cc996c25f..9991134c1 100644 --- a/CMake/MethaneUtils.cmake +++ b/CMake/MethaneUtils.cmake @@ -17,7 +17,7 @@ limitations under the License. ******************************************************************************* FILE: MethaneUtils.cmake -Cmake utilitary functions +Cmake utility functions *****************************************************************************]] diff --git a/CMakeLists.txt b/CMakeLists.txt index 473e54642..7e7a76697 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.11.0) +cmake_minimum_required(VERSION 3.13.0) project(MethaneKit) @@ -8,23 +8,26 @@ option(METHANE_USE_OPEN_IMAGE_IO "Enable using OpenImageIO library for images lo option(METHANE_ITT_INSTRUMENTATION_ENABLED "Enable ITT instrumentation" OFF) option(METHANE_SCOPE_TIMERS_ENABLED "Enable low-overhead profiling with scope-timers" OFF) option(METHANE_SHADERS_CODEVIEW_ENABLED "Enable shaders code symbols viewing in debug tools)" OFF) +option(METHANE_COMMAND_EXECUTION_LOGGING "Enable command execution debug logging" OFF) option(METHANE_RUN_TESTS_DURING_BUILD "Run tests during build" ON) -set(METHANE_VERSION "0.2" CACHE STRING "Methane release major-minor version number") -set(METHANE_BUILD_NUMBER "000000" CACHE STRING "Methane release build number") +set(METHANE_VERSION_MAJOR 0 CACHE STRING "Methane major version") +set(METHANE_VERSION_MINOR 3 CACHE STRING "Methane minor version") +set(METHANE_VERSION_BUILD 0 CACHE STRING "Methane build version") -set(METHANE_PRODUCT_NAME "Methane Kit (https://github.com/egorodet/MethaneKit)") -set(METHANE_COPYRIGHT "Copyright 2019-2020 Evgeny Gorodetskiy") - -include_directories($ENV{INCLUDE}) -link_directories($ENV{LIB} ${CMAKE_LIBRARY_INPUT_DIRECTORY}) +set(METHANE_VERSION_SHORT "${METHANE_VERSION_MAJOR}.${METHANE_VERSION_MINOR}") +set(METHANE_VERSION_FULL "${METHANE_VERSION_SHORT}.${METHANE_VERSION_BUILD}") +set(METHANE_PRODUCT_NAME "Methane Kit (https://github.com/egorodet/MethaneKit)") +set(METHANE_COPYRIGHT "Copyright 2019-2020 Evgeny Gorodetskiy") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" + "${CMAKE_CURRENT_SOURCE_DIR}/Externals/CMakeModules" "${CMAKE_CURRENT_SOURCE_DIR}/Externals/Catch2/single_include/cmake" "${CMAKE_CURRENT_SOURCE_DIR}/Externals/CMRC" ) +include(MethaneUtils) include(ParseAndAddCatchTests) set(CMAKE_CXX_STANDARD 17) @@ -33,15 +36,29 @@ set(PARSE_CATCH_TESTS_VERBOSE OFF) if(MSVC) - if(NOT DEFINED ENV{WindowsSdkVerBinPath}) - message(FATAL_ERROR "Windows SDK binary directory path is undefined! " - "Please start cmake generation from \"Visual Studio Native Tools\" command prompt.") + include(FindWindowsSDK) + if(WINDOWSSDK_FOUND) + message(STATUS "${WINDOWSSDK_LATEST_NAME} was selected for build") + else() + message(FATAL_ERROR "Windows SDK was not found!") + endif() + + get_windowssdk_include_dirs(${WINDOWSSDK_LATEST_DIR} WINDOWSSDK_INCLUDE_DIRS) + if(NOT WINDOWSSDK_INCLUDE_DIRS) + message(FATAL_ERROR "Failed to get Windows SDK include directories from ${WINDOWSSDK_LATEST_DIR}") + endif() + + get_windowssdk_library_dirs(${WINDOWSSDK_LATEST_DIR} WINDOWSSDK_LIBRARY_DIRS) + if(NOT WINDOWSSDK_LIBRARY_DIRS) + message(FATAL_ERROR "Failed to get Windows SDK library directories from ${WINDOWSSDK_LATEST_DIR}") endif() - set(VS_STARTUP_PROJECT MethaneShadowCube) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") - set(WINDOWS_SDK_BIN_PATH $ENV{WindowsSdkVerBinPath}x64) + set(VS_STARTUP_PROJECT MethaneAsteroids) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") # use /MT static runtime linking + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") # enable multi-threaded build + include_directories(${WINDOWSSDK_INCLUDE_DIRS}) + link_directories(${WINDOWSSDK_LIBRARY_DIRS}) add_definitions(-DUNICODE -D_UNICODE -DNOMINMAX -DWIN32_LEAN_AND_MEAN -DUSE_PIX) elseif(APPLE) @@ -51,10 +68,16 @@ elseif(APPLE) endif() -message(STATUS "Methane Kit version ${METHANE_VERSION} build number ${METHANE_BUILD_NUMBER}") +message(STATUS "Methane Kit version ${METHANE_VERSION_FULL}") +split_by_first_delimiter("${METHANE_VERSION_BUILD}" "." METHANE_VERSION_BUILD_MAJOR METHANE_VERSION_BUILD_MINOR) +add_definitions( + -DMETHANE_VERSION_MAJOR=${METHANE_VERSION_MAJOR} + -DMETHANE_VERSION_MINOR=${METHANE_VERSION_MINOR} + -DMETHANE_VERSION_BUILD=${METHANE_VERSION_BUILD_MAJOR} +) if(METHANE_USE_OPEN_IMAGE_IO) - message(STATUS "Methane Kit OpenImageIO media-library is enbabled.") + message(STATUS "Methane Kit OpenImageIO media-library is enabled.") endif() if(METHANE_ITT_INSTRUMENTATION_ENABLED) @@ -75,6 +98,11 @@ if(METHANE_RUN_TESTS_DURING_BUILD) message(STATUS "Methane tests running during build is enabled") endif() +if(METHANE_COMMAND_EXECUTION_LOGGING) + message(STATUS "Methane command execution debug logging is enabled") + add_definitions(-DCOMMAND_EXECUTION_LOGGING) +endif() + if (CMAKE_INSTALL_PREFIX AND EXISTS "${CMAKE_INSTALL_PREFIX}/bin/ctest") set(CTEST_EXE "${CMAKE_INSTALL_PREFIX}/bin/ctest") else() diff --git a/CMakeSettings.json b/CMakeSettings.json index 4214febf2..21f1758d1 100644 --- a/CMakeSettings.json +++ b/CMakeSettings.json @@ -24,6 +24,21 @@ "name": "METHANE_SHADERS_CODEVIEW_ENABLED", "value": "True", "type": "BOOL" + }, + { + "name": "METHANE_RUN_TESTS_DURING_BUILD", + "value": "False", + "type": "BOOL" + }, + { + "name": "METHANE_COMMAND_EXECUTION_LOGGING", + "value": "false", + "type": "BOOL" + }, + { + "name": "METHANE_USE_OPEN_IMAGE_IO", + "value": "false", + "type": "BOOL" } ] }, @@ -51,6 +66,21 @@ "name": "METHANE_SHADERS_CODEVIEW_ENABLED", "value": "True", "type": "BOOL" + }, + { + "name": "METHANE_RUN_TESTS_DURING_BUILD", + "value": "False", + "type": "BOOL" + }, + { + "name": "METHANE_USE_OPEN_IMAGE_IO", + "value": "false", + "type": "BOOL" + }, + { + "name": "METHANE_COMMAND_EXECUTION_LOGGING", + "value": "false", + "type": "BOOL" } ] }, @@ -78,6 +108,21 @@ "name": "METHANE_SHADERS_CODEVIEW_ENABLED", "value": "True", "type": "BOOL" + }, + { + "name": "METHANE_RUN_TESTS_DURING_BUILD", + "value": "False", + "type": "BOOL" + }, + { + "name": "METHANE_COMMAND_EXECUTION_LOGGING", + "value": "false", + "type": "BOOL" + }, + { + "name": "METHANE_USE_OPEN_IMAGE_IO", + "value": "false", + "type": "BOOL" } ] }, @@ -105,6 +150,21 @@ "name": "METHANE_SHADERS_CODEVIEW_ENABLED", "value": "True", "type": "BOOL" + }, + { + "name": "METHANE_RUN_TESTS_DURING_BUILD", + "value": "False", + "type": "BOOL" + }, + { + "name": "METHANE_COMMAND_EXECUTION_LOGGING", + "value": "False", + "type": "BOOL" + }, + { + "name": "METHANE_USE_OPEN_IMAGE_IO", + "value": "false", + "type": "BOOL" } ] }, diff --git a/Externals b/Externals index f9c91bbbb..7d2b868b1 160000 --- a/Externals +++ b/Externals @@ -1 +1 @@ -Subproject commit f9c91bbbb721bc1c1cfec0581dc123bee1457f0e +Subproject commit 7d2b868b196384282173bbbc34c3fb169377a4b7 diff --git a/Modules/CMakeLists.txt b/Modules/CMakeLists.txt index 3ac6dc0db..658edfab1 100644 --- a/Modules/CMakeLists.txt +++ b/Modules/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(Common) add_subdirectory(Data) add_subdirectory(Platform) add_subdirectory(Graphics) diff --git a/Modules/Common/CMakeLists.txt b/Modules/Common/CMakeLists.txt new file mode 100644 index 000000000..e9f96997e --- /dev/null +++ b/Modules/Common/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(Primitives) +add_subdirectory(Instrumentation) \ No newline at end of file diff --git a/Modules/Data/Instrumentation/CMakeLists.txt b/Modules/Common/Instrumentation/CMakeLists.txt similarity index 84% rename from Modules/Data/Instrumentation/CMakeLists.txt rename to Modules/Common/Instrumentation/CMakeLists.txt index f0b1d67c5..9ff57d14b 100644 --- a/Modules/Data/Instrumentation/CMakeLists.txt +++ b/Modules/Common/Instrumentation/CMakeLists.txt @@ -1,12 +1,12 @@ -set(TARGET MethaneDataInstrumentation) +set(TARGET MethaneInstrumentation) include(MethaneModules) -get_module_dirs("Methane/Data") +get_module_dirs("Methane") set(HEADERS ${INCLUDE_DIR}/Instrumentation.h - ${INCLUDE_DIR}/Timer.hpp + ${INCLUDE_DIR}/IttApiHelper.h ${INCLUDE_DIR}/ScopeTimer.h ${INCLUDE_DIR}/ILogger.h ) @@ -30,7 +30,8 @@ target_include_directories(${TARGET} target_link_libraries(${TARGET} PUBLIC - IttNotify + MethaneCommonPrimitives + ittnotify nowide_static ) diff --git a/Modules/Data/Instrumentation/Include/Methane/Data/ILogger.h b/Modules/Common/Instrumentation/Include/Methane/ILogger.h similarity index 89% rename from Modules/Data/Instrumentation/Include/Methane/Data/ILogger.h rename to Modules/Common/Instrumentation/Include/Methane/ILogger.h index e0e70ea95..b127826b7 100644 --- a/Modules/Data/Instrumentation/Include/Methane/Data/ILogger.h +++ b/Modules/Common/Instrumentation/Include/Methane/ILogger.h @@ -16,23 +16,20 @@ limitations under the License. ******************************************************************************* -FILE: Methane/Data/ILogger.h +FILE: Methane/ILogger.h Abstract logger interface. ******************************************************************************/ #pragma once -#include #include -namespace Methane::Data +namespace Methane { struct ILogger { - using Ptr = std::shared_ptr; - virtual void Log(const std::string& message) = 0; virtual ~ILogger() = default; diff --git a/Modules/Data/Instrumentation/Include/Methane/Data/Instrumentation.h b/Modules/Common/Instrumentation/Include/Methane/Instrumentation.h similarity index 91% rename from Modules/Data/Instrumentation/Include/Methane/Data/Instrumentation.h rename to Modules/Common/Instrumentation/Include/Methane/Instrumentation.h index 97b54415e..70d3dee75 100644 --- a/Modules/Data/Instrumentation/Include/Methane/Data/Instrumentation.h +++ b/Modules/Common/Instrumentation/Include/Methane/Instrumentation.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ Defines common ITT domain required for instrumentation. #pragma once -#include +#include "IttApiHelper.h" +#include "ScopeTimer.h" ITT_DOMAIN_EXTERN(); diff --git a/Modules/Common/Instrumentation/Include/Methane/IttApiHelper.h b/Modules/Common/Instrumentation/Include/Methane/IttApiHelper.h new file mode 100644 index 000000000..690944dcd --- /dev/null +++ b/Modules/Common/Instrumentation/Include/Methane/IttApiHelper.h @@ -0,0 +1,270 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/IttNotifyHelper.h +Helper macro-definitions for ITT instrumentation + +******************************************************************************/ + +#pragma once + +// Enable instrumentation of the ITT function arguments +//#define ITT_FUNCTION_ARGS_ENABLED + +#ifdef ITT_INSTRUMENTATION_ENABLED + +#include +#include +#include +#include + +#define INTEL_ITTNOTIFY_API_PRIVATE +#include + +#if ITT_PLATFORM==ITT_PLATFORM_WIN +#include +#endif + +#ifdef _WIN32 +#define UNICODE_AGNOSTIC(name) name##A +#else +#define UNICODE_AGNOSTIC(name) name +#endif + +namespace Methane::ITT +{ + +class Event +{ +protected: + __itt_id m_id = __itt_null; + const __itt_domain* m_p_domain; + +public: + Event(const __itt_domain* p_domain, __itt_string_handle* p_name) + : m_id(__itt_id_make(const_cast<__itt_domain*>(p_domain), reinterpret_cast(p_name))) + , m_p_domain(p_domain) + { } + + template + typename std::enable_if::value, void>::type AddArg(__itt_string_handle* p_name, const T& value) + { + double double_value = value; + __itt_metadata_add(m_p_domain, m_id, p_name, __itt_metadata_double, 1, &double_value); + } + + void AddArg(__itt_string_handle* p_name, int64_t value) + { + __itt_metadata_add(m_p_domain, m_id, p_name, __itt_metadata_s64, 1, &value); + } + + void AddArg(__itt_string_handle* p_name, const char* value) + { +#if ITT_PLATFORM==ITT_PLATFORM_WIN && (defined(UNICODE) || defined(_UNICODE)) + // string value must be converted to wchar_t + __itt_metadata_str_add(m_p_domain, m_id, p_name, nowide::widen(value).c_str(), 0); +#else + __itt_metadata_str_add(m_p_domain, m_id, p_name, value, 0); +#endif + } + + void AddArg(__itt_string_handle* p_name, void const* const pValue) + { + __itt_metadata_add(m_p_domain, m_id, p_name, __itt_metadata_unknown, 1, const_cast(pValue)); + } +}; + +class Marker : public Event +{ +public: + enum Scope + { + Global = __itt_scope_global, + Process = __itt_scope_track_group, + Thread =__itt_scope_track, + Task =__itt_scope_task, //means a task that will long until another marker with task scope in this thread occurs + }; + + Marker(const __itt_domain* p_domain, const char* p_name, Scope scope) + : Marker(p_domain, UNICODE_AGNOSTIC(__itt_string_handle_create)(p_name), scope) + { } + + void Notify() const + { + __itt_marker(m_p_domain, m_id, m_p_name, m_scope); + } + +private: + Marker(const __itt_domain* p_domain, __itt_string_handle* p_itt_name, Scope scope) + : Event(p_domain, p_itt_name) + , m_p_name(p_itt_name) + , m_scope(static_cast<__itt_scope>(scope)) + { } + + __itt_string_handle* m_p_name; + __itt_scope m_scope; +}; + +template +class Task : public Event +{ +public: + Task(const __itt_domain* p_domain, __itt_string_handle* p_name) + : Event(p_domain, p_name) + { + if (bRegion) + { + __itt_region_begin(m_p_domain, m_id, __itt_null, p_name); + } + else + { + __itt_task_begin(m_p_domain, m_id, __itt_null, p_name); + } + } + + ~Task() + { + if (bRegion) + { + __itt_region_end(m_p_domain, m_id); + } + else + { + __itt_task_end(m_p_domain); + } + } +}; + +#define ITT_DOMAIN_LOCAL(/*const char* */domain)\ + static const __itt_domain* __itt_domain_instance = UNICODE_AGNOSTIC(__itt_domain_create)(domain) + +#define ITT_DOMAIN_GLOBAL(/*const char* */domain)\ + const char* __itt_domain_name = domain;\ + __itt_domain* __itt_domain_instance = nullptr + +#define ITT_DOMAIN_EXTERN()\ + extern const char* __itt_domain_name;\ + extern __itt_domain* __itt_domain_instance + +#define ITT_DOMAIN_INIT()\ + if (!__itt_domain_instance && __itt_domain_name)\ + __itt_domain_instance = UNICODE_AGNOSTIC(__itt_domain_create)(__itt_domain_name) + +#if defined(_MSC_VER) && _MSC_VER >= 1900 //since VS 2015 magic statics are supported, TODO: check with other compilers + #define ITT_MAGIC_STATIC(static_variable) +#else +//the 'while' below is to protect code from crash in multi-threaded environment under compiler without magic statics support + #define ITT_MAGIC_STATIC(static_variable) while(!(static_variable)) std::this_thread::yield(); +#endif + +#define ITT_SCOPE(region, name)\ + static __itt_string_handle* __itt_scope_name = UNICODE_AGNOSTIC(__itt_string_handle_create)(name);\ + ITT_MAGIC_STATIC(__itt_scope_name);\ + ITT_DOMAIN_INIT();\ + Methane::ITT::Task __itt_scope_item(__itt_domain_instance, __itt_scope_name) + +#define ITT_SCOPE_TASK(/*const char* */name) ITT_SCOPE(false, name) +#define ITT_SCOPE_REGION(/*const char* */name) ITT_SCOPE(true, name) + +#ifdef ITT_FUNCTION_ARGS_ENABLED + +#define ITT_ARG(/*const char* */name, /*number or string*/ value) {\ + static __itt_string_handle* __itt_arg_name = UNICODE_AGNOSTIC(__itt_string_handle_create)(name);\ + ITT_MAGIC_STATIC(__itt_arg_name);\ + __itt_scope_item.AddArg(__itt_arg_name, value);\ +} + +#define ITT_FUNCTION_TASK() ITT_SCOPE_TASK(__FUNCTION__); ITT_ARG("__file__", __FILE__); ITT_ARG("__line__", __LINE__) + +#else + +#define ITT_ARG(/*const char* */name, /*number or string*/ value) +#define ITT_FUNCTION_TASK() ITT_SCOPE_TASK(__FUNCTION__) + +#endif + +#define ITT_MARKER(/*Methane::ITT::Marker::Scope*/scope, /*const char* */name)\ + ITT_DOMAIN_INIT();\ + static const Methane::ITT::Marker __itt_marker_item(__itt_domain_instance, name, scope);\ + __itt_marker_item.Notify() + +#define ITT_GLOBAL_MARKER(/*const char* */name) ITT_MARKER(Methane::ITT::Marker::Scope::Global, name) +#define ITT_PROCESS_MARKER(/*const char* */name) ITT_MARKER(Methane::ITT::Marker::Scope::Process, name) +#define ITT_THREAD_MARKER(/*const char* */name) ITT_MARKER(Methane::ITT::Marker::Scope::Thread, name) +#define ITT_TASK_MARKER(/*const char* */name) ITT_MARKER(Methane::ITT::Marker::Scope::Task, name) + +#define ITT_FUNCTION_MARKER(/*Methane::ITT::Marker::Scope*/scope) ITT_MARKER(scope, __FUNCTION__); +#define ITT_FUNCTION_GLOBAL_MARKER() ITT_FUNCTION_MARKER(Methane::ITT::Marker::Scope::Global) +#define ITT_FUNCTION_PROCESS_MARKER() ITT_FUNCTION_MARKER(Methane::ITT::Marker::Scope::Process) +#define ITT_FUNCTION_THREAD_MARKER() ITT_FUNCTION_MARKER(Methane::ITT::Marker::Scope::Thread) +#define ITT_FUNCTION_TASK_MARKER() ITT_FUNCTION_MARKER(Methane::ITT::Marker::Scope::Task) + +#define ITT_COUNTER(/*const char* */name, /*double */value) { \ + static __itt_string_handle* __itt_counter_name = UNICODE_AGNOSTIC(__itt_string_handle_create)(name);\ + ITT_MAGIC_STATIC(__itt_counter_name);\ + double counter_value = value;\ + ITT_DOMAIN_INIT();\ + __itt_metadata_add(__itt_domain_instance, __itt_null, __itt_counter_name, __itt_metadata_double, 1, &counter_value);\ +} + +class ScopeTrack +{ +public: + ScopeTrack(__itt_track* track) + { + __itt_set_track(track); + } + ~ScopeTrack() + { + __itt_set_track(nullptr); + } +}; + +//'group' defines virtual process (null means current process), track defines virtual thread +#define ITT_SCOPE_TRACK(/*const char* */group, /*const char* */ track)\ + static __itt_track* itt_track_name = __itt_track_create(__itt_track_group_create(((group) ? UNICODE_AGNOSTIC(__itt_string_handle_create)(group) : nullptr), __itt_track_group_type_normal), UNICODE_AGNOSTIC(__itt_string_handle_create)(track), __itt_track_type_normal);\ + ITT_MAGIC_STATIC(itt_track_name);\ + Methane::ITT::ScopeTrack itt_track(itt_track_name); + +} // namespace Methane::ITT + +#else + +#define ITT_DOMAIN_LOCAL(domain) +#define ITT_DOMAIN_GLOBAL(domain) +#define ITT_DOMAIN_EXTERN() +#define ITT_DOMAIN_INIT() +#define ITT_SCOPE(region, name) +#define ITT_SCOPE_TASK(name) +#define ITT_SCOPE_REGION(name) +#define ITT_FUNCTION_TASK() +#define ITT_ARG(name, value) +#define ITT_MARKER(scope, name) +#define ITT_GLOBAL_MARKER(name) +#define ITT_PROCESS_MARKER(name) +#define ITT_THREAD_MARKER(name) +#define ITT_FUNCTION_MARKER(scope) +#define ITT_FUNCTION_GLOBAL_MARKER() +#define ITT_FUNCTION_PROCESS_MARKER() +#define ITT_FUNCTION_THREAD_MARKER() +#define ITT_FUNCTION_TASK_MARKER() +#define ITT_TASK_MARKER(name) +#define ITT_COUNTER(name, value) +#define ITT_SCOPE_TRACK(group, track) + +#endif diff --git a/Modules/Data/Instrumentation/Include/Methane/Data/ScopeTimer.h b/Modules/Common/Instrumentation/Include/Methane/ScopeTimer.h similarity index 76% rename from Modules/Data/Instrumentation/Include/Methane/Data/ScopeTimer.h rename to Modules/Common/Instrumentation/Include/Methane/ScopeTimer.h index efa7d197c..3fa92084d 100644 --- a/Modules/Data/Instrumentation/Include/Methane/Data/ScopeTimer.h +++ b/Modules/Common/Instrumentation/Include/Methane/ScopeTimer.h @@ -16,20 +16,22 @@ limitations under the License. ******************************************************************************* -FILE: Methane/Data/ScopeTimer.h +FILE: Methane/ScopeTimer.h Code scope measurement timer with aggregating and averaging of timings. ******************************************************************************/ #pragma once -#include "Timer.hpp" #include "ILogger.h" +#include +#include + #include #include -namespace Methane::Data +namespace Methane { class ScopeTimer : protected Timer @@ -47,8 +49,8 @@ class ScopeTimer : protected Timer static Aggregator& Get(); ~Aggregator(); - void SetLogger(ILogger::Ptr sp_logger) { m_sp_logger = std::move(sp_logger); } - const ILogger::Ptr& GetLogger() const { return m_sp_logger; } + void SetLogger(Ptr sp_logger) { m_sp_logger = std::move(sp_logger); } + const Ptr& GetLogger() const { return m_sp_logger; } void AddScopeTiming(const std::string& scope_name, TimeDuration duration); const Timing& GetScopeTiming(const std::string& scope_name) const; @@ -62,7 +64,7 @@ class ScopeTimer : protected Timer using ScopeTimings = std::map; ScopeTimings m_timing_by_scope_name; - ILogger::Ptr m_sp_logger; + Ptr m_sp_logger; }; template @@ -80,18 +82,20 @@ class ScopeTimer : protected Timer std::string m_scope_name; }; +} // namespace Methane + #ifdef SCOPE_TIMERS_ENABLED -#define SCOPE_TIMER(SCOPE_NAME) Methane::Data::ScopeTimer scope_timer(SCOPE_NAME) +#define SCOPE_TIMER_INITIALIZE(LOGGER_TYPE) Methane::ScopeTimer::InitializeLogger() +#define SCOPE_TIMER(SCOPE_NAME) Methane::ScopeTimer scope_timer(SCOPE_NAME) #define FUNCTION_SCOPE_TIMER() SCOPE_TIMER(__func__) -#define FLUSH_SCOPE_TIMINGS() Methane::Data::ScopeTimer::Aggregator::Get().Flush() +#define FLUSH_SCOPE_TIMINGS() Methane::ScopeTimer::Aggregator::Get().Flush() -#else +#else // ifdef SCOPE_TIMERS_ENABLED +#define SCOPE_TIMER_INITIALIZE(LOGGER_TYPE) #define SCOPE_TIMER(SCOPE_NAME) #define FUNCTION_SCOPE_TIMER() #define FLUSH_SCOPE_TIMINGS() -#endif - -} // namespace Methane::Data +#endif // ifdef SCOPE_TIMERS_ENABLED diff --git a/Modules/Data/Instrumentation/Sources/Methane/Data/Instrumentation.cpp b/Modules/Common/Instrumentation/Sources/Methane/Instrumentation.cpp similarity index 88% rename from Modules/Data/Instrumentation/Sources/Methane/Data/Instrumentation.cpp rename to Modules/Common/Instrumentation/Sources/Methane/Instrumentation.cpp index c8b847c4c..c2f37a3d1 100644 --- a/Modules/Data/Instrumentation/Sources/Methane/Data/Instrumentation.cpp +++ b/Modules/Common/Instrumentation/Sources/Methane/Instrumentation.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,12 +16,12 @@ limitations under the License. ******************************************************************************* -FILE: Methane/Graphics/Instrumentation.cpp +FILE: Methane/Instrumentation.cpp Common header for instrumentation of the Methane Kit modules with ITT macroses, Defines common ITT domain required for instrumentation. ******************************************************************************/ -#include +#include ITT_DOMAIN_GLOBAL("Methane Kit"); diff --git a/Modules/Data/Instrumentation/Sources/Methane/Data/ScopeTimer.cpp b/Modules/Common/Instrumentation/Sources/Methane/ScopeTimer.cpp similarity index 90% rename from Modules/Data/Instrumentation/Sources/Methane/Data/ScopeTimer.cpp rename to Modules/Common/Instrumentation/Sources/Methane/ScopeTimer.cpp index 6ccedd075..6039bc21c 100644 --- a/Modules/Data/Instrumentation/Sources/Methane/Data/ScopeTimer.cpp +++ b/Modules/Common/Instrumentation/Sources/Methane/ScopeTimer.cpp @@ -16,24 +16,24 @@ limitations under the License. ******************************************************************************* -FILE: Methane/Graphics/ScopeTimer.cpp +FILE: Methane/ScopeTimer.cpp Code scope measurement timer with aggregating and averaging of timings. ******************************************************************************/ -#include -#include +#include + +#include #include #include -namespace Methane::Data +namespace Methane { ScopeTimer::Aggregator& ScopeTimer::Aggregator::Get() { ITT_FUNCTION_TASK(); - static Aggregator s_scope_aggregator; return s_scope_aggregator; } @@ -46,6 +46,7 @@ ScopeTimer::Aggregator::~Aggregator() void ScopeTimer::Aggregator::Flush() { + ITT_FUNCTION_TASK(); if (m_sp_logger) { LogTimings(*m_sp_logger); @@ -88,9 +89,9 @@ const ScopeTimer::Aggregator::Timing& ScopeTimer::Aggregator::GetScopeTiming(con { ITT_FUNCTION_TASK(); - static Timing g_empty_timing = {}; - auto scope_timing_it = m_timing_by_scope_name.find(scope_name); - return scope_timing_it != m_timing_by_scope_name.end() ? scope_timing_it->second : g_empty_timing; + static Timing s_empty_timing = {}; + auto scope_timing_it = m_timing_by_scope_name.find(scope_name); + return scope_timing_it != m_timing_by_scope_name.end() ? scope_timing_it->second : s_empty_timing; } ScopeTimer::ScopeTimer(std::string scope_name) @@ -106,4 +107,4 @@ ScopeTimer::~ScopeTimer() Aggregator::Get().AddScopeTiming(m_scope_name, GetElapsedDuration()); } -} +} // namespace Methane diff --git a/Modules/Common/Primitives/CMakeLists.txt b/Modules/Common/Primitives/CMakeLists.txt new file mode 100644 index 000000000..3d43e4d88 --- /dev/null +++ b/Modules/Common/Primitives/CMakeLists.txt @@ -0,0 +1,44 @@ +set(TARGET MethaneCommonPrimitives) + +include(MethaneModules) + +get_module_dirs("Methane") + +set(HEADERS + ${INCLUDE_DIR}/Version.h + ${INCLUDE_DIR}/Memory.hpp + ${INCLUDE_DIR}/Timer.hpp +) + +set(SOURCES + ${SOURCES_DIR}/Common.cpp +) + +add_library(${TARGET} STATIC + ${HEADERS} + ${SOURCES} +) + +target_include_directories(${TARGET} + PRIVATE + Sources + PUBLIC + Include +) + +source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${HEADERS} ${SOURCES}) + +set_target_properties(${TARGET} + PROPERTIES + FOLDER Modules/Common + PUBLIC_HEADER "${HEADERS}" +) + +install(TARGETS ${TARGET} + PUBLIC_HEADER + DESTINATION ${INCLUDE_DIR} + COMPONENT Development + ARCHIVE + DESTINATION Lib + COMPONENT Development +) \ No newline at end of file diff --git a/Modules/Common/Primitives/Include/Methane/Memory.hpp b/Modules/Common/Primitives/Include/Methane/Memory.hpp new file mode 100644 index 000000000..c6d639399 --- /dev/null +++ b/Modules/Common/Primitives/Include/Methane/Memory.hpp @@ -0,0 +1,57 @@ +/****************************************************************************** + +Copyright 2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Memory.hpp +Methane memory handling smart pointers and references. + +******************************************************************************/ + +#pragma once + +#include +#include +#include + +namespace Methane +{ + +template +using Ptr = std::shared_ptr; + +template +using Ptrs = std::vector>; + +template +using WeakPtr = std::weak_ptr; + +template +using WeakPtrs = std::vector>; + +template +using UniquePtr = std::unique_ptr; + +template +using UniquePtrs = std::vector>; + +template +using Ref = std::reference_wrapper; + +template +using Refs = std::vector>; + +} // namespace Methane \ No newline at end of file diff --git a/Modules/Data/Instrumentation/Include/Methane/Data/Timer.hpp b/Modules/Common/Primitives/Include/Methane/Timer.hpp similarity index 87% rename from Modules/Data/Instrumentation/Include/Methane/Data/Timer.hpp rename to Modules/Common/Primitives/Include/Methane/Timer.hpp index 898447692..24630f355 100644 --- a/Modules/Data/Instrumentation/Include/Methane/Data/Timer.hpp +++ b/Modules/Common/Primitives/Include/Methane/Timer.hpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,11 +23,9 @@ Basic animation timer for measuring elapsed time since start. #pragma once -#include "Instrumentation.h" - #include -namespace Methane::Data +namespace Methane { class Timer @@ -37,7 +35,7 @@ class Timer using TimePoint = Clock::time_point; using TimeDuration = Clock::duration; - Timer() : m_start_time(Clock::now()) { ITT_FUNCTION_TASK(); } + Timer() : m_start_time(Clock::now()) { } TimePoint GetStartTime() const noexcept { return m_start_time; } TimeDuration GetElapsedDuration() const noexcept { return Clock::now() - m_start_time; } @@ -48,14 +46,18 @@ class Timer template T GetElapsedSeconds() const noexcept { - ITT_FUNCTION_TASK(); return std::chrono::duration_cast>(GetElapsedDuration()).count(); } void Reset() noexcept { - ITT_FUNCTION_TASK(); - m_start_time = Clock::now(); + Reset(Clock::now()); + } + +protected: + void Reset(TimePoint time_point) + { + m_start_time = time_point; } private: diff --git a/Modules/Common/Primitives/Include/Methane/Version.h b/Modules/Common/Primitives/Include/Methane/Version.h new file mode 100644 index 000000000..2311523a7 --- /dev/null +++ b/Modules/Common/Primitives/Include/Methane/Version.h @@ -0,0 +1,44 @@ +/****************************************************************************** + +Copyright 2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Version.h +Methane version macro definitions + +******************************************************************************/ + +#pragma once + +#ifndef METHANE_VERSION_MAJOR +#define METHANE_VERSION_MAJOR 0 +#endif + +#ifndef METHANE_VERSION_MINOR +#define METHANE_VERSION_MINOR 0 +#endif + +#ifndef METHANE_VERSION_BUILD +#define METHANE_VERSION_BUILD 0 +#endif + +#define VAL_TO_STR_HELPER(VALUE) #VALUE +#define VAL_TO_STR(VALUE) VAL_TO_STR_HELPER(VALUE) + +#define METHANE_VERSION_MAJOR_STR VAL_TO_STR(METHANE_VERSION_MAJOR) +#define METHANE_VERSION_MINOR_STR VAL_TO_STR(METHANE_VERSION_MINOR) +#define METHANE_VERSION_BUILD_STR VAL_TO_STR(METHANE_VERSION_BUILD) +#define METHANE_VERSION_STR METHANE_VERSION_MAJOR_STR "." METHANE_VERSION_MINOR_STR "." METHANE_VERSION_BUILD_STR \ No newline at end of file diff --git a/Modules/Common/Primitives/Sources/Methane/Common.cpp b/Modules/Common/Primitives/Sources/Methane/Common.cpp new file mode 100644 index 000000000..46de4bea9 --- /dev/null +++ b/Modules/Common/Primitives/Sources/Methane/Common.cpp @@ -0,0 +1,36 @@ +/****************************************************************************** + +Copyright 2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Common.cpp +Methane Common dummy function. + +******************************************************************************/ + +namespace Methane +{ +namespace Common +{ + +void Dummy() +{ + // Prevents libtool warning for library: + // the table of contents is empty (no object file members in the library define global symbols) +} + +} +} // namespace Methane::Data \ No newline at end of file diff --git a/Modules/Data/Animation/CMakeLists.txt b/Modules/Data/Animation/CMakeLists.txt index d10e8eccf..627cc3138 100644 --- a/Modules/Data/Animation/CMakeLists.txt +++ b/Modules/Data/Animation/CMakeLists.txt @@ -31,7 +31,8 @@ target_include_directories(${TARGET} target_link_libraries(${TARGET} PUBLIC - MethaneDataInstrumentation + MethaneCommonPrimitives + MethaneInstrumentation ) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${HEADERS} ${SOURCES}) diff --git a/Modules/Data/Animation/Include/Methane/Data/Animation.h b/Modules/Data/Animation/Include/Methane/Data/Animation.h index d1ad4c737..a2b3d676e 100644 --- a/Modules/Data/Animation/Include/Methane/Data/Animation.h +++ b/Modules/Data/Animation/Include/Methane/Data/Animation.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,9 +23,7 @@ Abstract animation class #pragma once -#include - -#include +#include namespace Methane::Data { @@ -33,13 +31,17 @@ namespace Methane::Data class Animation : public Timer { public: - using Ptr = std::shared_ptr; - using WeakPtr = std::weak_ptr; + enum class State : uint32_t + { + Running = 0u, + Paused, + Completed, + }; Animation(double duration_sec = std::numeric_limits::max()); virtual ~Animation(); - bool IsRunning() const noexcept { return m_is_running; } + State GetState() const noexcept { return m_state; } double GetDuration() const noexcept { return m_duration_sec; } void SetDuration(double duration_sec) { m_duration_sec = duration_sec; } void IncreaseDuration(double duration_sec); @@ -48,11 +50,18 @@ class Animation : public Timer virtual void Stop() noexcept; virtual bool Update() = 0; + void Pause(); + void Resume(); + protected: + bool IsTimeOver() const noexcept { return GetElapsedSecondsD() >= m_duration_sec; } + using Timer::Reset; - bool m_is_running = true; - double m_duration_sec = std::numeric_limits::max(); +private: + State m_state = State::Running; + double m_duration_sec = std::numeric_limits::max(); + TimeDuration m_paused_duration; }; } // namespace Methane::Data diff --git a/Modules/Data/Animation/Include/Methane/Data/AnimationsPool.h b/Modules/Data/Animation/Include/Methane/Data/AnimationsPool.h index 9a0fce804..8f267123c 100644 --- a/Modules/Data/Animation/Include/Methane/Data/AnimationsPool.h +++ b/Modules/Data/Animation/Include/Methane/Data/AnimationsPool.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,6 +23,8 @@ Pool of animations for centralized updating, adding and removing in application. #pragma once +#include + #include "Animation.h" #include @@ -30,12 +32,17 @@ Pool of animations for centralized updating, adding and removing in application. namespace Methane::Data { -using Animations = std::deque; +using Animations = std::deque>; class AnimationsPool : public Animations { public: void Update(); + void Pause(); + void Resume(); + +private: + bool m_is_paused = false; }; } // namespace Methane::Data diff --git a/Modules/Data/Animation/Include/Methane/Data/TimeAnimation.h b/Modules/Data/Animation/Include/Methane/Data/TimeAnimation.h index d37904d17..f429f85ef 100644 --- a/Modules/Data/Animation/Include/Methane/Data/TimeAnimation.h +++ b/Modules/Data/Animation/Include/Methane/Data/TimeAnimation.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ limitations under the License. ******************************************************************************* FILE: Methane/Data/TimeAnimation.h -Time-based animation of any external enity with an update lambda-function. +Time-based animation of any external entity with an update lambda-function. ******************************************************************************/ diff --git a/Modules/Data/Animation/Include/Methane/Data/ValueAnimation.hpp b/Modules/Data/Animation/Include/Methane/Data/ValueAnimation.hpp index 70fc665db..fa9184603 100644 --- a/Modules/Data/Animation/Include/Methane/Data/ValueAnimation.hpp +++ b/Modules/Data/Animation/Include/Methane/Data/ValueAnimation.hpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ Abstract value animation based on time with an update lambda-function. #include "Animation.h" -#include +#include #include @@ -62,16 +62,18 @@ class ValueAnimation : public Animation bool Update() override { ITT_FUNCTION_TASK(); - if (!m_is_running) + if (GetState() != State::Running) return false; const double elapsed_seconds = GetElapsedSecondsD(); const double delta_seconds = elapsed_seconds - m_prev_elapsed_seconds; - m_is_running = elapsed_seconds < m_duration_sec && - m_update_function(m_value, m_start_value, elapsed_seconds, delta_seconds); + if (IsTimeOver() || !m_update_function(m_value, m_start_value, elapsed_seconds, delta_seconds)) + { + Stop(); + } m_prev_elapsed_seconds = elapsed_seconds; - return m_is_running; + return GetState() == State::Running; } private: diff --git a/Modules/Data/Animation/Sources/Methane/Data/Animation.cpp b/Modules/Data/Animation/Sources/Methane/Data/Animation.cpp index 147bb0307..ab639202f 100644 --- a/Modules/Data/Animation/Sources/Methane/Data/Animation.cpp +++ b/Modules/Data/Animation/Sources/Methane/Data/Animation.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,13 +22,16 @@ Pool of animations for centralized updating, adding and removing in application. ******************************************************************************/ #include -#include +#include + +#include namespace Methane::Data { Animation::Animation(double duration_sec) - : m_duration_sec(duration_sec) + : Timer() + , m_duration_sec(duration_sec) { ITT_FUNCTION_TASK(); } @@ -47,14 +50,32 @@ void Animation::IncreaseDuration(double duration_sec) void Animation::Restart() noexcept { ITT_FUNCTION_TASK(); - m_is_running = true; + m_state = State::Running; Timer::Reset(); } void Animation::Stop() noexcept { ITT_FUNCTION_TASK(); - m_is_running = false; + m_state = State::Completed; +} + +void Animation::Pause() +{ + if (m_state != State::Running) + throw std::logic_error("Only running animation can be paused."); + + m_state = State::Paused; + m_paused_duration = GetElapsedDuration(); +} + +void Animation::Resume() +{ + if (m_state != State::Paused) + throw std::logic_error("Only paused animation can be resumed."); + + m_state = State::Running; + Reset(Clock::now() - m_paused_duration); } } // namespace Methane::Data diff --git a/Modules/Data/Animation/Sources/Methane/Data/AnimationsPool.cpp b/Modules/Data/Animation/Sources/Methane/Data/AnimationsPool.cpp index f3c711fd3..abd7b11ba 100644 --- a/Modules/Data/Animation/Sources/Methane/Data/AnimationsPool.cpp +++ b/Modules/Data/Animation/Sources/Methane/Data/AnimationsPool.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ Pool of animations for centralized updating, adding and removing in application. ******************************************************************************/ #include -#include +#include #include @@ -32,13 +32,13 @@ namespace Methane::Data void AnimationsPool::Update() { ITT_FUNCTION_TASK(); - if (empty()) + if (m_is_paused || empty()) return; std::vector completed_animation_indices; for (size_t animation_index = 0; animation_index < size(); ++animation_index) { - Animation::Ptr& sp_animation = (*this)[animation_index]; + Ptr& sp_animation = (*this)[animation_index]; if (!sp_animation || !sp_animation->Update()) { completed_animation_indices.push_back(animation_index); @@ -53,4 +53,32 @@ void AnimationsPool::Update() } } +void AnimationsPool::Pause() +{ + if (m_is_paused) + return; + + for(const Ptr& sp_animation : *this) + { + if (sp_animation->GetState() == Animation::State::Running) + sp_animation->Pause(); + } + + m_is_paused = true; +} + +void AnimationsPool::Resume() +{ + if (!m_is_paused) + return; + + for(const Ptr& sp_animation : *this) + { + if (sp_animation->GetState() == Animation::State::Paused) + sp_animation->Resume(); + } + + m_is_paused = false; +} + } // namespace Methane::Data diff --git a/Modules/Data/Animation/Sources/Methane/Data/TimeAnimation.cpp b/Modules/Data/Animation/Sources/Methane/Data/TimeAnimation.cpp index eb5234271..ab96ad8fb 100644 --- a/Modules/Data/Animation/Sources/Methane/Data/TimeAnimation.cpp +++ b/Modules/Data/Animation/Sources/Methane/Data/TimeAnimation.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,12 +17,12 @@ limitations under the License. ******************************************************************************* FILE: Methane/Data/TimeAnimation.cpp -Time-based animation of any external enity with an update lambda-function. +Time-based animation of any external entity with an update lambda-function. ******************************************************************************/ #include -#include +#include namespace Methane::Data { @@ -44,16 +44,18 @@ void TimeAnimation::Restart() noexcept bool TimeAnimation::Update() { ITT_FUNCTION_TASK(); - if (!m_is_running) + if (GetState() != State::Running) return false; const double elapsed_seconds = GetElapsedSecondsD(); const double delta_seconds = elapsed_seconds - m_prev_elapsed_seconds; - m_is_running = elapsed_seconds < m_duration_sec && - m_update_function(elapsed_seconds, delta_seconds); + if (IsTimeOver() || !m_update_function(elapsed_seconds, delta_seconds)) + { + Stop(); + } m_prev_elapsed_seconds = elapsed_seconds; - return m_is_running; + return GetState() == State::Running; } } // namespace Methane::Data diff --git a/Modules/Data/CMakeLists.txt b/Modules/Data/CMakeLists.txt index fc8b83c18..fb5b50802 100644 --- a/Modules/Data/CMakeLists.txt +++ b/Modules/Data/CMakeLists.txt @@ -1,4 +1,3 @@ -add_subdirectory(Instrumentation) add_subdirectory(Primitives) add_subdirectory(RangeSet) add_subdirectory(Animation) diff --git a/Modules/Data/Primitives/CMakeLists.txt b/Modules/Data/Primitives/CMakeLists.txt index 32c256a5b..67b272141 100644 --- a/Modules/Data/Primitives/CMakeLists.txt +++ b/Modules/Data/Primitives/CMakeLists.txt @@ -6,6 +6,7 @@ get_module_dirs("Methane/Data") set(HEADERS ${INCLUDE_DIR}/Types.h + ${INCLUDE_DIR}/Chunk.h ${INCLUDE_DIR}/Provider.h ${INCLUDE_DIR}/FileProvider.hpp ${INCLUDE_DIR}/ResourceProvider.hpp @@ -32,7 +33,7 @@ target_include_directories(${TARGET} ) target_link_libraries(${TARGET} - MethaneDataInstrumentation + MethaneInstrumentation MethanePlatformUtils CML ) diff --git a/Modules/Data/Primitives/Include/Methane/Data/AlignedAllocator.hpp b/Modules/Data/Primitives/Include/Methane/Data/AlignedAllocator.hpp index 0fa09e15d..ab2d5e5b5 100644 --- a/Modules/Data/Primitives/Include/Methane/Data/AlignedAllocator.hpp +++ b/Modules/Data/Primitives/Include/Methane/Data/AlignedAllocator.hpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Data/Primitives/Include/Methane/Data/AppResourceProviders.h b/Modules/Data/Primitives/Include/Methane/Data/AppResourceProviders.h index 5a1e71a7b..0e133fa7b 100644 --- a/Modules/Data/Primitives/Include/Methane/Data/AppResourceProviders.h +++ b/Modules/Data/Primitives/Include/Methane/Data/AppResourceProviders.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Data/Primitives/Include/Methane/Data/Chunk.h b/Modules/Data/Primitives/Include/Methane/Data/Chunk.h new file mode 100644 index 000000000..a7c206c7a --- /dev/null +++ b/Modules/Data/Primitives/Include/Methane/Data/Chunk.h @@ -0,0 +1,44 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Data/Chunk.h +Data chunk representing owning or non-owning memory container + +******************************************************************************/ + +#pragma once + +#include "Types.h" + +namespace Methane::Data +{ + +struct Chunk +{ + // NOTE: Data storage is used only when data is not managed by data provider and returned with chunk (when data is loaded from file, for example) + const Bytes data; + ConstRawPtr p_data = nullptr; + const Size size = 0; + + Chunk() = default; + Chunk(ConstRawPtr in_p_data, Size in_size) : p_data(in_p_data), size(in_size) { } + Chunk(const Bytes&& in_data) : data(std::move(in_data)), p_data(static_cast(data.data())), size(static_cast(data.size())) { } + Chunk(Chunk&& other) noexcept : data(std::move(other.data)), p_data(data.empty() ? other.p_data : data.data()), size(data.empty() ? other.size : static_cast(data.size())) { } +}; + +} // namespace Methane::Data diff --git a/Modules/Data/Primitives/Include/Methane/Data/FileProvider.hpp b/Modules/Data/Primitives/Include/Methane/Data/FileProvider.hpp index 69fd2ea84..ce5dc90b7 100644 --- a/Modules/Data/Primitives/Include/Methane/Data/FileProvider.hpp +++ b/Modules/Data/Primitives/Include/Methane/Data/FileProvider.hpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ Singleton data provider of files on disk. #include "Provider.h" #include -#include +#include #include #include @@ -48,7 +48,7 @@ class FileProvider : public Provider bool HasData(const std::string& path) const noexcept override { ITT_FUNCTION_TASK(); - return std::ifstream(GetDataFilePath(path)).good();; + return std::ifstream(GetDataFilePath(path)).good(); } Data::Chunk GetData(const std::string& path) const override diff --git a/Modules/Data/Primitives/Include/Methane/Data/Math.hpp b/Modules/Data/Primitives/Include/Methane/Data/Math.hpp index d0c395975..a83546301 100644 --- a/Modules/Data/Primitives/Include/Methane/Data/Math.hpp +++ b/Modules/Data/Primitives/Include/Methane/Data/Math.hpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Data/Primitives/Include/Methane/Data/Parallel.hpp b/Modules/Data/Primitives/Include/Methane/Data/Parallel.hpp index 5d4e4318c..043d75749 100644 --- a/Modules/Data/Primitives/Include/Methane/Data/Parallel.hpp +++ b/Modules/Data/Primitives/Include/Methane/Data/Parallel.hpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -52,28 +52,12 @@ namespace Methane::Data template struct IteratorFunction { - using type = std::function; + using Type = std::function; }; -#if 0 // TODO: fix or remove experimental code - -template::iterator_category>> -struct is_const_iterator -{ - static constexpr bool value = std::is_const::value_type>::value; -}; - -template -struct IteratorFunction::value, const typename std::iterator_traits::value_type>>; - -template -struct IteratorFunction::value, typename std::iterator_traits::value_type>>; - -#endif - template void ParallelForEach(const Iterator& begin_it, const Iterator& end_it, - typename IteratorFunction::type&& body_function) + typename IteratorFunction::Type&& body_function) { ITT_FUNCTION_TASK(); @@ -109,7 +93,7 @@ void ParallelForEach(const Iterator& begin_it, const Iterator& end_it, for(const std::future& future : futures) { future.wait(); - }; + } #endif } @@ -130,9 +114,9 @@ void ParallelFor(IndexType begin_index, IndexType end_index, std::function(std::thread::hardware_concurrency()); - const IndexType chunk_size = Data::DivCeil(count, hw_theads_count); + const IndexType count = end_index - begin_index; + const IndexType hw_threads_count = static_cast(std::thread::hardware_concurrency()); + const IndexType chunk_size = Data::DivCeil(count, hw_threads_count); std::vector> futures; futures.reserve(static_cast(count)); @@ -156,7 +140,7 @@ void ParallelFor(IndexType begin_index, IndexType end_index, std::function& future : futures) { future.wait(); - }; + } #endif } diff --git a/Modules/Data/Primitives/Include/Methane/Data/Provider.h b/Modules/Data/Primitives/Include/Methane/Data/Provider.h index 4bdc28245..8111d9361 100644 --- a/Modules/Data/Primitives/Include/Methane/Data/Provider.h +++ b/Modules/Data/Primitives/Include/Methane/Data/Provider.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,23 +23,12 @@ Data provider interface used for loading application resources and resource file #pragma once -#include "Types.h" +#include "Chunk.h" -namespace Methane::Data -{ +#include -struct Chunk +namespace Methane::Data { - // NOTE: Data storage is used only when data is not managed by data provider and returned with chunk (when data is loaded from file, for example) - const Bytes data; - ConstRawPtr p_data = nullptr; - const Size size = 0; - - Chunk() = default; - Chunk(ConstRawPtr in_p_data, Size in_size) : p_data(in_p_data), size(in_size) { } - Chunk(const Bytes&& in_data) : data(std::move(in_data)), p_data(static_cast(data.data())), size(static_cast(data.size())) { } - Chunk(Chunk&& other) noexcept : data(std::move(other.data)), p_data(data.empty() ? other.p_data : data.data()), size(data.empty() ? other.size : static_cast(data.size())) { } -}; struct Provider { diff --git a/Modules/Data/Primitives/Include/Methane/Data/ResourceProvider.hpp b/Modules/Data/Primitives/Include/Methane/Data/ResourceProvider.hpp index 3aa6c1751..0f97ebd85 100644 --- a/Modules/Data/Primitives/Include/Methane/Data/ResourceProvider.hpp +++ b/Modules/Data/Primitives/Include/Methane/Data/ResourceProvider.hpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ from RESOURCES_NAMESPACE or external resource files on disk. #include "FileProvider.hpp" -#include +#include #include #include diff --git a/Modules/Data/Primitives/Include/Methane/Data/Types.h b/Modules/Data/Primitives/Include/Methane/Data/Types.h index 430cc292e..2e897f5b1 100644 --- a/Modules/Data/Primitives/Include/Methane/Data/Types.h +++ b/Modules/Data/Primitives/Include/Methane/Data/Types.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -37,18 +37,18 @@ class Point2T : public cml::vector> using Base = cml::vector>; using Base::Base; - T x() const noexcept { return (*this)[0]; } - T y() const noexcept { return (*this)[1]; } + T GetX() const noexcept { return (*this)[0]; } + T GetY() const noexcept { return (*this)[1]; } - void setX(T x) noexcept { (*this)[0] = x; } - void setY(T y) noexcept { (*this)[1] = y; } + void SetX(T x) noexcept { (*this)[0] = x; } + void SetY(T y) noexcept { (*this)[1] = y; } template explicit operator Point2T() const - { return Point2T(static_cast(x()), static_cast(y())); } + { return Point2T(static_cast(GetX()), static_cast(GetY())); } operator std::string() const - { return "Pt(" + std::to_string(x()) + ", " + std::to_string(y()) + ")"; } + { return "Pt(" + std::to_string(GetX()) + ", " + std::to_string(GetY()) + ")"; } }; using Point2i = Point2T; diff --git a/Modules/Data/Primitives/Sources/Methane/Data/Types.cpp b/Modules/Data/Primitives/Sources/Methane/Data/Types.cpp index f2fc3d907..541cd1098 100644 --- a/Modules/Data/Primitives/Sources/Methane/Data/Types.cpp +++ b/Modules/Data/Primitives/Sources/Methane/Data/Types.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ FILE: Methane/Data/Types.cpp namespace Methane::Data { -void dummy() +void Dummy() { // Prevents libtool warning for library: // the table of contents is empty (no object file members in the library define global symbols) diff --git a/Modules/Data/RangeSet/CMakeLists.txt b/Modules/Data/RangeSet/CMakeLists.txt index 77b404471..5f9c2c880 100644 --- a/Modules/Data/RangeSet/CMakeLists.txt +++ b/Modules/Data/RangeSet/CMakeLists.txt @@ -23,7 +23,7 @@ target_include_directories(${TARGET} target_link_libraries(${TARGET} PUBLIC - MethaneDataInstrumentation + MethaneInstrumentation ) set_target_properties(${TARGET} diff --git a/Modules/Data/RangeSet/Include/Methane/Data/Range.hpp b/Modules/Data/RangeSet/Include/Methane/Data/Range.hpp index 64e650993..161ac669b 100644 --- a/Modules/Data/RangeSet/Include/Methane/Data/Range.hpp +++ b/Modules/Data/RangeSet/Include/Methane/Data/Range.hpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ limitations under the License. FILE: Methane/Data/Range.hpp -Range data type representing continuos numeric multitude from start (inclusively) +Range data type representing continuous numeric multitude from start (inclusively) till end (exclusively): [start, end) ******************************************************************************/ @@ -28,10 +28,9 @@ till end (exclusively): [start, end) #include #include #include -#include #include -#include +#include namespace Methane::Data { @@ -57,15 +56,15 @@ class Range bool IsAdjacent(const Range& other) const { ITT_FUNCTION_TASK(); return m_start == other.m_end || other.m_start == m_end; } bool IsOverlapping(const Range& other) const { ITT_FUNCTION_TASK(); return m_start < other.m_end && other.m_start < m_end; } - bool IsMergable(const Range& other) const { ITT_FUNCTION_TASK(); return m_start <= other.m_end && other.m_start <= m_end; } + bool IsMergeable(const Range& other) const { ITT_FUNCTION_TASK(); return m_start <= other.m_end && other.m_start <= m_end; } bool Contains(const Range& other) const { ITT_FUNCTION_TASK(); return m_start <= other.m_start && other.m_end <= m_end; } Range operator+(const Range& other) const // merge { ITT_FUNCTION_TASK(); - if (!IsMergable(other)) + if (!IsMergeable(other)) { - throw std::invalid_argument("Can not merge: ranges are not mergable."); + throw std::invalid_argument("Can not merge: ranges are not mergeable."); } return Range(std::min(m_start, other.m_start), std::max(m_end, other.m_end)); } @@ -73,7 +72,7 @@ class Range Range operator%(const Range& other) const // intersect { ITT_FUNCTION_TASK(); - if (!IsMergable(other)) + if (!IsMergeable(other)) { throw std::invalid_argument("Can not intersect: ranges are not overlapping or adjacent."); } @@ -102,12 +101,6 @@ class Range return ss.str(); } - explicit operator const char*() const - { - ITT_FUNCTION_TASK(); - return std::string(*this).c_str(); - } - protected: void Validate() const { diff --git a/Modules/Data/RangeSet/Include/Methane/Data/RangeSet.hpp b/Modules/Data/RangeSet/Include/Methane/Data/RangeSet.hpp index d3cf2392a..c6b0cac79 100644 --- a/Modules/Data/RangeSet/Include/Methane/Data/RangeSet.hpp +++ b/Modules/Data/RangeSet/Include/Methane/Data/RangeSet.hpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ limitations under the License. FILE: Methane/Data/RangeSet.hpp Set of ranges with operations of adding and removing a range with maintaining -minimum number of continous ranges by merging or splitting adjacent ranges in set +minimum number of continuous ranges by merging or splitting adjacent ranges in set ******************************************************************************/ @@ -27,7 +27,7 @@ minimum number of continous ranges by merging or splitting adjacent ranges in se #include "Range.hpp" -#include +#include #include #include @@ -71,7 +71,7 @@ class RangeSet : protected std::set> { ITT_FUNCTION_TASK(); Range merged_range(range); - const RangeOfRanges ranges = GetMergableRanges(range); + const RangeOfRanges ranges = GetMergeableRanges(range); Ranges remove_ranges; for (auto range_it = ranges.first; range_it != ranges.second; ++range_it) @@ -88,7 +88,7 @@ class RangeSet : protected std::set> { ITT_FUNCTION_TASK(); Ranges remove_ranges, add_ranges; - RangeOfRanges ranges = GetMergableRanges(range); + RangeOfRanges ranges = GetMergeableRanges(range); for (auto range_it = ranges.first; range_it != ranges.second; ++range_it) { if (!range.IsOverlapping(*range_it)) @@ -129,7 +129,7 @@ class RangeSet : protected std::set> protected: using RangeOfRanges = std::pair; - RangeOfRanges GetMergableRanges(const Range& range) + RangeOfRanges GetMergeableRanges(const Range& range) { ITT_FUNCTION_TASK(); if (BaseSet::empty()) @@ -137,28 +137,28 @@ class RangeSet : protected std::set> return RangeOfRanges{ BaseSet::end(), BaseSet::end() }; } - RangeOfRanges mergable_ranges = { + RangeOfRanges mergeable_ranges = { BaseSet::lower_bound(Range(range.GetStart(), range.GetStart())), BaseSet::upper_bound(range) }; - if (mergable_ranges.first != BaseSet::begin()) - mergable_ranges.first--; + if (mergeable_ranges.first != BaseSet::begin()) + mergeable_ranges.first--; - while (mergable_ranges.first != BaseSet::end() && !range.IsMergable(*mergable_ranges.first)) - mergable_ranges.first++; + while (mergeable_ranges.first != BaseSet::end() && !range.IsMergeable(*mergeable_ranges.first)) + mergeable_ranges.first++; - if (mergable_ranges.first == BaseSet::end()) + if (mergeable_ranges.first == BaseSet::end()) return RangeOfRanges(BaseSet::end(), BaseSet::end()); - while (mergable_ranges.second != mergable_ranges.first && - (mergable_ranges.second == BaseSet::end() || !range.IsMergable(*mergable_ranges.second))) + while (mergeable_ranges.second != mergeable_ranges.first && + (mergeable_ranges.second == BaseSet::end() || !range.IsMergeable(*mergeable_ranges.second))) { - mergable_ranges.second--; + mergeable_ranges.second--; } - mergable_ranges.second++; + mergeable_ranges.second++; - return mergable_ranges; + return mergeable_ranges; } using Ranges = std::vector>; diff --git a/Modules/Data/RangeSet/Sources/Methane/Data/RangeSet.cpp b/Modules/Data/RangeSet/Sources/Methane/Data/RangeSet.cpp index a7dd22bfe..d963c8f54 100644 --- a/Modules/Data/RangeSet/Sources/Methane/Data/RangeSet.cpp +++ b/Modules/Data/RangeSet/Sources/Methane/Data/RangeSet.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ FILE: Methane/Data/RangeSet.cpp namespace Methane::Data { -void dummy() +void Dummy() { // Prevents libtool warning for library on MacOS: // the table of contents is empty (no object file members in the library define global symbols) diff --git a/Modules/Data/RangeSet/Test/Main.cpp b/Modules/Data/RangeSet/Test/Main.cpp index b3ff3427d..e8ff8c408 100644 --- a/Modules/Data/RangeSet/Test/Main.cpp +++ b/Modules/Data/RangeSet/Test/Main.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Data/RangeSet/Test/RangeSetTest.cpp b/Modules/Data/RangeSet/Test/RangeSetTest.cpp index 6aa8f07c8..44bc2b2ee 100644 --- a/Modules/Data/RangeSet/Test/RangeSetTest.cpp +++ b/Modules/Data/RangeSet/Test/RangeSetTest.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -61,7 +61,7 @@ TEST_CASE("Range set add", "[range-set]") { 0, 2 }, { 4, 8 }, { 11, 12 }, { 17, 20 }, { 25, 29 } }; - SECTION("Adding non-mergable range") + SECTION("Adding non-mergeable range") { RangeSet range_set(test_range_set); range_set.Add({ 14, 16 }); @@ -70,7 +70,7 @@ TEST_CASE("Range set add", "[range-set]") CHECK(range_set == reference_set); } - SECTION("Adding mergable range in the middle") + SECTION("Adding mergeable range in the middle") { RangeSet range_set(test_range_set); range_set.Add({ 5, 12 }); @@ -79,7 +79,7 @@ TEST_CASE("Range set add", "[range-set]") CHECK(range_set == reference_set); } - SECTION("Adding mergable range in the beginning") + SECTION("Adding mergeable range in the beginning") { RangeSet range_set(test_range_set); range_set.Add({ 0, 7 }); @@ -88,7 +88,7 @@ TEST_CASE("Range set add", "[range-set]") CHECK(range_set == reference_set); } - SECTION("Adding mergable range in the end") + SECTION("Adding mergeable range in the end") { RangeSet range_set(test_range_set); range_set.Add({ 26, 35 }); @@ -97,7 +97,7 @@ TEST_CASE("Range set add", "[range-set]") CHECK(range_set == reference_set); } - SECTION("Adding adacent range in the middle") + SECTION("Adding adjacent range in the middle") { RangeSet range_set(test_range_set); range_set.Add({ 8, 11 }); diff --git a/Modules/Data/RangeSet/Test/RangeTest.cpp b/Modules/Data/RangeSet/Test/RangeTest.cpp index 753831f56..249c341fa 100644 --- a/Modules/Data/RangeSet/Test/RangeTest.cpp +++ b/Modules/Data/RangeSet/Test/RangeTest.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -112,16 +112,16 @@ TEST_CASE("Range relations", "[range]") CHECK_FALSE(range_d.IsOverlapping(range_a)); } - SECTION("Mergable") + SECTION("Mergeable") { - CHECK(range_a.IsMergable(range_c)); - CHECK(range_c.IsMergable(range_a)); + CHECK(range_a.IsMergeable(range_c)); + CHECK(range_c.IsMergeable(range_a)); - CHECK(range_a.IsMergable(range_b)); - CHECK(range_b.IsMergable(range_a)); + CHECK(range_a.IsMergeable(range_b)); + CHECK(range_b.IsMergeable(range_a)); - CHECK_FALSE(range_a.IsMergable(range_d)); - CHECK_FALSE(range_d.IsMergable(range_a)); + CHECK_FALSE(range_a.IsMergeable(range_d)); + CHECK_FALSE(range_d.IsMergeable(range_a)); } SECTION("Contained") diff --git a/Modules/Graphics/App/CMakeLists.txt b/Modules/Graphics/App/CMakeLists.txt index 70b63279a..78966e676 100644 --- a/Modules/Graphics/App/CMakeLists.txt +++ b/Modules/Graphics/App/CMakeLists.txt @@ -3,12 +3,15 @@ set(TARGET MethaneGraphicsApp) get_module_dirs("Methane/Graphics") set(HEADERS + ${INCLUDE_DIR}/App.h ${INCLUDE_DIR}/App.hpp + ${INCLUDE_DIR}/AppController.h ${INCLUDE_DIR}/AppCameraController.h ${INCLUDE_DIR}/AppContextController.h ) set(SOURCES + ${SOURCES_DIR}/AppController.cpp ${SOURCES_DIR}/AppCameraController.cpp ${SOURCES_DIR}/AppContextController.cpp ) @@ -31,7 +34,7 @@ target_link_libraries(${TARGET} MethanePlatformUtils MethaneGraphicsCore MethaneGraphicsHelpers - MethaneDataInstrumentation + MethaneInstrumentation ) set_target_properties(${TARGET} diff --git a/Modules/Graphics/App/Include/Methane/Graphics/App.h b/Modules/Graphics/App/Include/Methane/Graphics/App.h new file mode 100644 index 000000000..417eb1c89 --- /dev/null +++ b/Modules/Graphics/App/Include/Methane/Graphics/App.h @@ -0,0 +1,49 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/App.hpp +Interface of the graphics application base template class defined in App.hpp + +******************************************************************************/ + +#pragma once + +#include + +namespace Methane::Graphics +{ + +struct IApp +{ + struct Settings + { + RenderPass::Access::Mask screen_pass_access = RenderPass::Access::None; + bool animations_enabled = true; + bool show_hud_in_window_title = true; + bool show_logo_badge = true; + int32_t default_device_index = 0; + }; + + virtual const IApp::Settings& GetGraphicsAppSettings() const noexcept = 0; + virtual bool SetAnimationsEnabled(bool animations_enabled) = 0; + virtual bool SetShowHudInWindowTitle(bool show_hud_in_window_title) = 0; + + virtual ~IApp() = default; +}; + +} // namespace Methane::Graphics \ No newline at end of file diff --git a/Modules/Graphics/App/Include/Methane/Graphics/App.hpp b/Modules/Graphics/App/Include/Methane/Graphics/App.hpp index 65ef08470..c630dc077 100644 --- a/Modules/Graphics/App/Include/Methane/Graphics/App.hpp +++ b/Modules/Graphics/App/Include/Methane/Graphics/App.hpp @@ -24,27 +24,29 @@ Base frame class provides frame buffer management with resize handling. #pragma once +#include "App.h" +#include "AppController.h" +#include "AppCameraController.h" #include "AppContextController.h" #include -#include +#include #include #include -#include #include #include -#include +#include #include -#include #include #include #include #include -#include +#include #include #include #include +#include #include namespace Methane::Graphics @@ -53,52 +55,50 @@ namespace Methane::Graphics struct AppFrame { const uint32_t index = 0; - Texture::Ptr sp_screen_texture; - RenderPass::Ptr sp_screen_pass; + Ptr sp_screen_texture; + Ptr sp_screen_pass; AppFrame(uint32_t frame_index) : index(frame_index) { ITT_FUNCTION_TASK(); } }; template class App - : public Platform::App - , public Context::Callback + : public Graphics::IApp + , public Platform::App + , public RenderContext::Callback { static_assert(std::is_base_of::value, "Application Frame type must be derived from AppFrame."); public: - struct Settings + + struct AllSettings { - Platform::App::Settings app; - Context::Settings context; - bool show_hud_in_window_title; - bool show_logo_badge; + Platform::App::Settings platform_app; + IApp::Settings graphics_app; + RenderContext::Settings render_context; }; - App(const Settings& settings, RenderPass::Access::Mask screen_pass_access, - const std::string& help_description = "Methane Graphics Application") - : Platform::App(settings.app) + explicit App(const AllSettings& settings, const std::string& help_description = "Methane Graphics Application") + : Platform::App(settings.platform_app) , m_image_loader(Data::TextureProvider::Get()) - , m_initial_context_settings(settings.context) - , m_screen_pass_access(screen_pass_access) - , m_show_hud_in_window_title(settings.show_hud_in_window_title) - , m_show_logo_badge(settings.show_logo_badge) + , m_settings(settings.graphics_app) + , m_initial_context_settings(settings.render_context) { ITT_FUNCTION_TASK(); - m_cmd_options.add_options() - ("d,hud", "Show/hide HUD in window title", cxxopts::value()) - ("v,vsync", "Enable/disable vertical synchronization", cxxopts::value()) - ("i,device", "Render at adapter index, use -1 for software adapter", cxxopts::value()) - ("f,framebuffers", "Frame buffers count in swap-chain", cxxopts::value()); + add_option("-i,--hud", m_settings.show_hud_in_window_title, "HUD information in window title", true); + add_option("-a,--animations", m_settings.animations_enabled, "Enable animations", true); + add_option("-d,--device", m_settings.default_device_index, "Render at adapter index, use -1 for software adapter", true); + add_option("-v,--vsync", m_initial_context_settings.vsync_enabled, "Vertical synchronization", true); + add_option("-b,--frame-buffers", m_initial_context_settings.frame_buffers_count, "Frame buffers count in swap-chain", true); - m_input_state.AddControllers({ std::make_shared(*this, help_description) }); + InputState().AddControllers({ std::make_shared(*this, help_description) }); } ~App() override { // WARNING: Don't forget to make the following call in the derived Application class // Wait for GPU rendering is completed to release resources - // m_sp_context->WaitForGpu(Context::WaitFor::RenderComplete); + // m_sp_context->WaitForGpu(RenderContext::WaitFor::RenderComplete); ITT_FUNCTION_TASK(); m_sp_context->RemoveCallback(*this); } @@ -107,23 +107,23 @@ class App void InitContext(const Platform::AppEnvironment& env, const FrameSize& frame_size) override { ITT_FUNCTION_TASK(); - const Devices& devices = System::Get().UpdateGpuDevices(); + const Ptrs& devices = System::Get().UpdateGpuDevices(); assert(!devices.empty()); - Device::Ptr sp_device = m_default_device_index < 0 + Ptr sp_device = m_settings.default_device_index < 0 ? System::Get().GetSoftwareGpuDevice() - : (static_cast(m_default_device_index) < devices.size() - ? devices[m_default_device_index] + : (static_cast(m_settings.default_device_index) < devices.size() + ? devices[m_settings.default_device_index] : devices.front()); assert(sp_device); // Create render context of the current window size m_initial_context_settings.frame_size = frame_size; - m_sp_context = Context::Create(env, *sp_device, m_initial_context_settings); - m_sp_context->SetName("App Graphics Context"); + m_sp_context = RenderContext::Create(env, *sp_device, m_initial_context_settings); + m_sp_context->SetName("App Render Context"); m_sp_context->AddCallback(*this); - m_input_state.AddControllers({ std::make_shared(*m_sp_context) }); + InputState().AddControllers({ std::make_shared(*m_sp_context) }); SetFullScreen(m_initial_context_settings.is_full_screen); } @@ -132,7 +132,7 @@ class App { ITT_FUNCTION_TASK(); assert(m_sp_context); - const Context::Settings& context_settings = m_sp_context->GetSettings(); + const RenderContext::Settings& context_settings = m_sp_context->GetSettings(); // Create depth texture for FB rendering if (context_settings.depth_stencil_format != PixelFormat::Unknown) @@ -179,14 +179,14 @@ class App : 1.f ), RenderPass::StencilAttachment(), - m_screen_pass_access + m_settings.screen_pass_access }); m_frames.emplace_back(std::move(frame)); } // Create Methane logo badge - if (m_show_logo_badge) + if (m_settings.show_logo_badge) m_sp_logo_badge = std::make_shared(*m_sp_context); Platform::App::Init(); @@ -195,59 +195,44 @@ class App bool Resize(const FrameSize& frame_size, bool is_minimized) override { ITT_FUNCTION_TASK(); - - struct ResourceInfo - { - Resource::DescriptorByUsage descriptor_by_usage; - std::string name; - }; if (!AppBase::Resize(frame_size, is_minimized)) return false; m_initial_context_settings.frame_size = frame_size; - // Save color texture information and delete obsolete resources for each frame buffer - std::vector frame_restore_info(m_frames.size()); + // Save frame and depth textures restore information and delete obsolete resources + std::vector frame_restore_infos; for (FrameT& frame : m_frames) { - assert(!!frame.sp_screen_texture); - - frame_restore_info[frame.index] = { - frame.sp_screen_texture->GetDescriptorByUsage(), - frame.sp_screen_texture->GetName() - }; - + frame_restore_infos.emplace_back(frame.sp_screen_texture); frame.sp_screen_texture.reset(); } - - // Save depth texture information and delete it - const Resource::DescriptorByUsage depth_descriptor_by_usage = m_sp_depth_texture ? m_sp_depth_texture->GetDescriptorByUsage() : Resource::DescriptorByUsage(); - const std::string depth_resource_name = m_sp_depth_texture ? m_sp_depth_texture->GetName() : std::string(); + const ResourceRestoreInfo depth_restore_info(m_sp_depth_texture); m_sp_depth_texture.reset(); // Resize render context assert(m_sp_context); m_sp_context->Resize(frame_size); - // Resize depth texture and update it in render pass - if (!depth_descriptor_by_usage.empty()) + // Restore depth texture with new size + if (!depth_restore_info.descriptor_by_usage.empty()) { - m_sp_depth_texture = Texture::CreateDepthStencilBuffer(*m_sp_context, depth_descriptor_by_usage); - m_sp_depth_texture->SetName(depth_resource_name); + m_sp_depth_texture = Texture::CreateDepthStencilBuffer(*m_sp_context, depth_restore_info.descriptor_by_usage); + m_sp_depth_texture->SetName(depth_restore_info.name); } - // Resize frame buffers by creating new color textures and updating them in render pass + // Restore frame buffers with new size and update textures in render pass settings for (FrameT& frame : m_frames) { - ResourceInfo& frame_info = frame_restore_info[frame.index]; - RenderPass::Settings pass_settings = frame.sp_screen_pass->GetSettings(); + ResourceRestoreInfo& frame_restore_info = frame_restore_infos[frame.index]; + RenderPass::Settings pass_settings = frame.sp_screen_pass->GetSettings(); - frame.sp_screen_texture = Texture::CreateFrameBuffer(*m_sp_context, frame.index, frame_info.descriptor_by_usage); - frame.sp_screen_texture->SetName(frame_info.name); + frame.sp_screen_texture = Texture::CreateFrameBuffer(*m_sp_context, frame.index, frame_restore_info.descriptor_by_usage); + frame.sp_screen_texture->SetName(frame_restore_info.name); pass_settings.color_attachments[0].wp_texture = frame.sp_screen_texture; - pass_settings.depth_attachment.wp_texture = m_sp_depth_texture; + pass_settings.depth_attachment.wp_texture = m_sp_depth_texture; frame.sp_screen_pass->Update(pass_settings); } @@ -261,12 +246,12 @@ class App bool Update() override { ITT_FUNCTION_TASK(); - if (m_is_minimized) + if (IsMinimized()) return false; System::Get().CheckForChanges(); + m_animations.Update(); - return true; } @@ -274,7 +259,7 @@ class App { ITT_FUNCTION_TASK(); - if (m_is_minimized) + if (IsMinimized()) { // No need to render frames while window is minimized. // Sleep thread for a while to not heat CPU by running the message loop @@ -282,38 +267,19 @@ class App return false; } - // Update HUD info in window title - if (!m_show_hud_in_window_title || - m_title_update_timer.GetElapsedSecondsD() < g_title_update_interval_sec) - return true; - if (!m_sp_context) { - throw std::runtime_error("Context is not initialized before rendering."); + throw std::runtime_error("RenderContext is not initialized before rendering."); } - const Context::Settings& context_settings = m_sp_context->GetSettings(); - const FpsCounter& fps_counter = m_sp_context->GetFpsCounter(); - const uint32_t average_fps = fps_counter.GetFramesPerSecond(); - const FpsCounter::FrameTiming average_frame_timing = fps_counter.GetAverageFrameTiming(); - - std::stringstream title_ss; - title_ss.precision(2); - title_ss << m_settings.name << " " - << average_fps << " FPS (" << std::fixed << average_frame_timing.GetTotalTimeMSec() - << " ms, " << std::fixed << average_frame_timing.GetCpuTimePercent() << "% cpu)" - << ", " << context_settings.frame_size.width << " x " << context_settings.frame_size.height - << ", " << std::to_string(context_settings.frame_buffers_count) << " FB" - << ", VSync: " << (context_settings.vsync_enabled ? "ON" : "OFF") - << ", GPU: " << m_sp_context->GetDevice().GetAdapterName() - << " (F1 - help)"; - - SetWindowTitle(title_ss.str()); - m_title_update_timer.Reset(); + // Update HUD info in window title + if (m_settings.show_hud_in_window_title && + m_title_update_timer.GetElapsedSecondsD() >= g_title_update_interval_sec) + { + UpdateWindowTitle(); + m_title_update_timer.Reset(); + } - // Keep window full-screen mode in sync with the context - SetFullScreen(context_settings.is_full_screen); - return true; } @@ -340,7 +306,7 @@ class App m_frames.clear(); m_sp_depth_texture.reset(); m_sp_logo_badge.reset(); - m_initialized = false; + Deinitialize(); } // Context::Callback interface @@ -350,40 +316,95 @@ class App Init(); } - void SetShowHudInWindowTitle(bool show_hud_in_window_title) { m_show_hud_in_window_title = show_hud_in_window_title; } - bool GetShowHudInWindowTitle() const { return m_show_hud_in_window_title; } + // Graphics::IApp interface + const IApp::Settings& GetGraphicsAppSettings() const noexcept override { return m_settings; } -protected: + bool SetAnimationsEnabled(bool animations_enabled) override + { + if (m_settings.animations_enabled == animations_enabled) + return false; - // AppBase interface + m_settings.animations_enabled = animations_enabled; - Platform::AppView GetView() const override + // Pause animations or resume from the paused state + if (m_settings.animations_enabled) + m_animations.Resume(); + else + m_animations.Pause(); + + // Disable all camera controllers while animations are paused, since they can not function without animations + Refs camera_controllers = InputState().template GetControllersOfType(); + for(const Ref camera_controller : camera_controllers) + { + camera_controller.get().SetEnabled(animations_enabled); + } + + return true; + } + + bool SetShowHudInWindowTitle(bool show_hud_in_window_title) override { - ITT_FUNCTION_TASK(); - return m_sp_context->GetAppView(); + if (m_settings.show_hud_in_window_title == show_hud_in_window_title) + return false; + + m_settings.show_hud_in_window_title = show_hud_in_window_title; + UpdateWindowTitle(); + + return true; } - void ParseCommandLine(const cxxopts::ParseResult& cmd_parse_result) override +protected: + struct ResourceRestoreInfo { - ITT_FUNCTION_TASK(); - Platform::App::ParseCommandLine(cmd_parse_result); + Resource::DescriptorByUsage descriptor_by_usage; + std::string name; + + ResourceRestoreInfo() = default; + ResourceRestoreInfo(const ResourceRestoreInfo&) = default; + explicit ResourceRestoreInfo(const Ptr& sp_resource) + : descriptor_by_usage(sp_resource ? sp_resource->GetDescriptorByUsage() : Resource::DescriptorByUsage()) + , name(sp_resource ? sp_resource->GetName() : std::string()) + { } + }; - if (cmd_parse_result.count("hud")) - { - m_show_hud_in_window_title = cmd_parse_result["hud"].as() != 0; - } - if (cmd_parse_result.count("vsync")) - { - m_initial_context_settings.vsync_enabled = cmd_parse_result["vsync"].as() != 0; - } - if (cmd_parse_result.count("device")) - { - m_default_device_index = cmd_parse_result["device"].as(); - } - if (cmd_parse_result.count("framebuffers")) + void UpdateWindowTitle() + { + if (!m_settings.show_hud_in_window_title) { - m_initial_context_settings.frame_buffers_count = cmd_parse_result["framebuffers"].as(); + SetWindowTitle(GetPlatformAppSettings().name); + return; } + + assert(m_sp_context); + if (!m_sp_context) + return; + + const RenderContext::Settings& context_settings = m_sp_context->GetSettings(); + const FpsCounter& fps_counter = m_sp_context->GetFpsCounter(); + const uint32_t average_fps = fps_counter.GetFramesPerSecond(); + const FpsCounter::FrameTiming average_frame_timing = fps_counter.GetAverageFrameTiming(); + + std::stringstream title_ss; + title_ss.precision(2); + title_ss << GetPlatformAppSettings().name + << " " << average_fps + << " FPS, " << std::fixed << average_frame_timing.GetTotalTimeMSec() + << " ms, " << std::fixed << average_frame_timing.GetCpuTimePercent() << "% cpu" + << " | " << context_settings.frame_size.width << " x " << context_settings.frame_size.height + << " | " << std::to_string(context_settings.frame_buffers_count) << " FB" + << " | VSync " << (context_settings.vsync_enabled ? "ON" : "OFF") + << " | " << m_sp_context->GetDevice().GetAdapterName() + << " | F1 - help"; + + SetWindowTitle(title_ss.str()); + } + + // AppBase interface + + Platform::AppView GetView() const override + { + ITT_FUNCTION_TASK(); + return m_sp_context->GetAppView(); } inline FrameT& GetCurrentFrame() @@ -394,7 +415,7 @@ class App return m_frames[frame_index]; } - const Context::Settings& GetInitialContextSettings() const { return m_initial_context_settings; } + const RenderContext::Settings& GetInitialContextSettings() const { return m_initial_context_settings; } static std::string IndexedName(const std::string& base_name, uint32_t index) { @@ -404,22 +425,20 @@ class App return ss.str(); } - Context::Ptr m_sp_context; - ImageLoader m_image_loader; - Texture::Ptr m_sp_depth_texture; - LogoBadge::Ptr m_sp_logo_badge; - std::vector m_frames; - Data::AnimationsPool m_animations; + ImageLoader m_image_loader; + Data::AnimationsPool m_animations; + + Ptr m_sp_context; + Ptr m_sp_depth_texture; + Ptr m_sp_logo_badge; + std::vector m_frames; private: - Context::Settings m_initial_context_settings; - int32_t m_default_device_index = 0; - const RenderPass::Access::Mask m_screen_pass_access; - bool m_show_hud_in_window_title; - bool m_show_logo_badge; - Data::Timer m_title_update_timer; - - static constexpr double g_title_update_interval_sec = 1; + IApp::Settings m_settings; + RenderContext::Settings m_initial_context_settings; + Timer m_title_update_timer; + + static constexpr double g_title_update_interval_sec = 1.0; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/App/Include/Methane/Graphics/AppCameraController.h b/Modules/Graphics/App/Include/Methane/Graphics/AppCameraController.h index e2e295d81..24f778c0a 100644 --- a/Modules/Graphics/App/Include/Methane/Graphics/AppCameraController.h +++ b/Modules/Graphics/App/Include/Methane/Graphics/AppCameraController.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/App/Include/Methane/Graphics/AppContextController.h b/Modules/Graphics/App/Include/Methane/Graphics/AppContextController.h index 1a6ae75be..3c2b48620 100644 --- a/Modules/Graphics/App/Include/Methane/Graphics/AppContextController.h +++ b/Modules/Graphics/App/Include/Methane/Graphics/AppContextController.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -31,13 +31,12 @@ Graphics context controller for switching parameters in runtime. namespace Methane::Graphics { -struct Context; +struct RenderContext; enum class AppContextAction : uint32_t { None = 0, - - SwitchFullScreen, + SwitchVSync, SwitchDevice, AddFrameBufferToSwapChain, @@ -52,14 +51,13 @@ class AppContextController final { public: inline static const ActionByKeyboardState default_action_by_keyboard_state = { - { { Platform::Keyboard::Key::LeftControl, Platform::Keyboard::Key::F }, AppContextAction::SwitchFullScreen }, { { Platform::Keyboard::Key::LeftControl, Platform::Keyboard::Key::V }, AppContextAction::SwitchVSync }, { { Platform::Keyboard::Key::LeftControl, Platform::Keyboard::Key::X }, AppContextAction::SwitchDevice }, { { Platform::Keyboard::Key::LeftControl, Platform::Keyboard::Key::Equal }, AppContextAction::AddFrameBufferToSwapChain }, { { Platform::Keyboard::Key::LeftControl, Platform::Keyboard::Key::Minus }, AppContextAction::RemoveFrameBufferFromSwapChain }, }; - AppContextController(Context& context, const ActionByKeyboardState& action_by_keyboard_state = default_action_by_keyboard_state); + AppContextController(RenderContext& context, const ActionByKeyboardState& action_by_keyboard_state = default_action_by_keyboard_state); // Input::Controller implementation void OnKeyboardChanged(Platform::Keyboard::Key, Platform::Keyboard::KeyState, const Platform::Keyboard::StateChange& state_change) override; @@ -71,7 +69,7 @@ class AppContextController final void OnKeyboardStateAction(AppContextAction action) override; std::string GetKeyboardActionName(AppContextAction action) const override; - Context& m_context; + RenderContext& m_context; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/App/Include/Methane/Graphics/AppController.h b/Modules/Graphics/App/Include/Methane/Graphics/AppController.h new file mode 100644 index 000000000..70d37ca0d --- /dev/null +++ b/Modules/Graphics/App/Include/Methane/Graphics/AppController.h @@ -0,0 +1,76 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/AppController.h +Base graphics application controller. + +******************************************************************************/ + +#pragma once + +#include "App.h" + +#include +#include + +namespace Methane::Graphics +{ + +enum class AppAction : uint32_t +{ + None = 0, + + SwitchAnimations, + SwitchWindowHud, + + Count +}; + +class AppController + : public Platform::AppController + , public Platform::Keyboard::ActionControllerBase +{ +public: + using ActionByKeyboardState = Platform::Keyboard::ActionControllerBase::ActionByKeyboardState; + inline static const ActionByKeyboardState default_action_by_keyboard_state = { + { { Platform::Keyboard::Key::LeftControl, Platform::Keyboard::Key::Z }, AppAction::SwitchAnimations }, + { { Platform::Keyboard::Key::LeftControl, Platform::Keyboard::Key::H }, AppAction::SwitchWindowHud }, + }; + + AppController(IApp& application, const std::string& application_help, + const Platform::AppController::ActionByKeyboardState& platform_action_by_keyboard_state = Platform::AppController::default_action_by_keyboard_state, + const Graphics::AppController::ActionByKeyboardState& graphics_action_by_keyboard_state = Graphics::AppController::default_action_by_keyboard_state); + + // Input::Controller implementation + void OnKeyboardChanged(Platform::Keyboard::Key, Platform::Keyboard::KeyState, const Platform::Keyboard::StateChange& state_change) override; + HelpLines GetHelp() const override; + +protected: + using Platform::AppController::OnKeyboardKeyAction; + using Platform::AppController::OnKeyboardStateAction; + using Platform::AppController::GetKeyboardActionName; + + // Keyboard::ActionControllerBase interface + void OnKeyboardKeyAction(AppAction, Platform::Keyboard::KeyState) override { } + void OnKeyboardStateAction(AppAction action) override; + std::string GetKeyboardActionName(AppAction action) const override; + + IApp& m_application; +}; + +} // namespace Methane::Platform diff --git a/Modules/Graphics/App/Sources/Methane/Graphics/AppCameraController.cpp b/Modules/Graphics/App/Sources/Methane/Graphics/AppCameraController.cpp index 2ea9d5d1d..cb0154b4c 100644 --- a/Modules/Graphics/App/Sources/Methane/Graphics/AppCameraController.cpp +++ b/Modules/Graphics/App/Sources/Methane/Graphics/AppCameraController.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ Action camera controller with keyboard and mouse interactions handling. ******************************************************************************/ #include -#include +#include using namespace Methane::Platform; diff --git a/Modules/Graphics/App/Sources/Methane/Graphics/AppContextController.cpp b/Modules/Graphics/App/Sources/Methane/Graphics/AppContextController.cpp index 807e791ca..66d3f992a 100644 --- a/Modules/Graphics/App/Sources/Methane/Graphics/AppContextController.cpp +++ b/Modules/Graphics/App/Sources/Methane/Graphics/AppContextController.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,10 +23,10 @@ Graphics context controller for switching parameters in runtime. #include -#include +#include #include #include -#include +#include #include @@ -35,7 +35,7 @@ using namespace Methane::Platform; namespace Methane::Graphics { -AppContextController::AppContextController(Context& context, const ActionByKeyboardState& action_by_keyboard_state) +AppContextController::AppContextController(RenderContext& context, const ActionByKeyboardState& action_by_keyboard_state) : Controller("GRAPHICS SETTINGS") , Keyboard::ActionControllerBase(action_by_keyboard_state, {}) , m_context(context) @@ -54,10 +54,6 @@ void AppContextController::OnKeyboardStateAction(AppContextAction action) ITT_FUNCTION_TASK(); switch (action) { - case AppContextAction::SwitchFullScreen: - m_context.SetFullScreen(!m_context.GetSettings().is_full_screen); - break; - case AppContextAction::SwitchVSync: m_context.SetVSyncEnabled(!m_context.GetSettings().vsync_enabled); break; @@ -72,7 +68,7 @@ void AppContextController::OnKeyboardStateAction(AppContextAction action) case AppContextAction::SwitchDevice: { - const Device::Ptr sp_next_device = System::Get().GetNextGpuDevice(m_context.GetDevice()); + const Ptr sp_next_device = System::Get().GetNextGpuDevice(m_context.GetDevice()); if (sp_next_device) { m_context.Reset(*sp_next_device); @@ -89,7 +85,6 @@ std::string AppContextController::GetKeyboardActionName(AppContextAction action) switch (action) { case AppContextAction::None: return "none"; - case AppContextAction::SwitchFullScreen: return "switch full-screen mode"; case AppContextAction::SwitchVSync: return "switch vertical synchronization"; case AppContextAction::SwitchDevice: return "switch device used for rendering"; case AppContextAction::AddFrameBufferToSwapChain: return "add frame buffer to swap-chain"; diff --git a/Modules/Graphics/App/Sources/Methane/Graphics/AppController.cpp b/Modules/Graphics/App/Sources/Methane/Graphics/AppController.cpp new file mode 100644 index 000000000..ae4cd72be --- /dev/null +++ b/Modules/Graphics/App/Sources/Methane/Graphics/AppController.cpp @@ -0,0 +1,90 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/AppController.cpp +Base graphics application controller + +******************************************************************************/ + +#include +#include +#include + +#include + +namespace Methane::Graphics +{ + +AppController::AppController(IApp& application, const std::string& application_help, + const Platform::AppController::ActionByKeyboardState& platform_action_by_keyboard_state, + const Graphics::AppController::ActionByKeyboardState& graphics_action_by_keyboard_state) + : Platform::AppController(dynamic_cast(application), application_help, platform_action_by_keyboard_state) + , Platform::Keyboard::ActionControllerBase(graphics_action_by_keyboard_state, {}) + , m_application(application) +{ + ITT_FUNCTION_TASK(); +} + +void AppController::OnKeyboardChanged(Platform::Keyboard::Key key, Platform::Keyboard::KeyState key_state, const Platform::Keyboard::StateChange& state_change) +{ + ITT_FUNCTION_TASK(); + Platform::AppController::OnKeyboardChanged(key, key_state, state_change); + Platform::Keyboard::ActionControllerBase::OnKeyboardChanged(key, key_state, state_change); +} + +void AppController::OnKeyboardStateAction(AppAction action) +{ + ITT_FUNCTION_TASK(); + switch(action) + { + case AppAction::SwitchAnimations: + m_application.SetAnimationsEnabled(!m_application.GetGraphicsAppSettings().animations_enabled); + break; + + case AppAction::SwitchWindowHud: + m_application.SetShowHudInWindowTitle(!m_application.GetGraphicsAppSettings().show_hud_in_window_title); + break; + + default: assert(0); + } +} + +std::string AppController::GetKeyboardActionName(AppAction action) const +{ + ITT_FUNCTION_TASK(); + switch (action) + { + case AppAction::None: return "none"; + case AppAction::SwitchAnimations: return "switch animations on/off"; + case AppAction::SwitchWindowHud: return "switch HUD in window title on/off"; + default: assert(0); + } + return ""; +} + +Platform::Input::IHelpProvider::HelpLines AppController::GetHelp() const +{ + ITT_FUNCTION_TASK(); + + HelpLines help_lines = Platform::AppController::GetHelp(); + const HelpLines gfx_help_lines = Platform::Keyboard::ActionControllerBase::GetKeyboardHelp(); + help_lines.insert(help_lines.end(), std::make_move_iterator(gfx_help_lines.begin()), std::make_move_iterator(gfx_help_lines.end())); + return help_lines; +} + +} // namespace Methane::Platform diff --git a/Modules/Graphics/Core/CMakeLists.txt b/Modules/Graphics/Core/CMakeLists.txt index 3a55de8a9..8336af225 100644 --- a/Modules/Graphics/Core/CMakeLists.txt +++ b/Modules/Graphics/Core/CMakeLists.txt @@ -11,12 +11,18 @@ if (WIN32) ${SOURCES_GRAPHICS_DIR}/TypesDX.cpp ${SOURCES_GRAPHICS_DIR}/DeviceDX.h ${SOURCES_GRAPHICS_DIR}/DeviceDX.cpp + ${SOURCES_GRAPHICS_DIR}/FenceDX.h + ${SOURCES_GRAPHICS_DIR}/FenceDX.cpp ${SOURCES_GRAPHICS_DIR}/ContextDX.h - ${SOURCES_GRAPHICS_DIR}/ContextDX.cpp + ${SOURCES_GRAPHICS_DIR}/ContextDX.hpp ${SOURCES_GRAPHICS_DIR}/ShaderDX.h ${SOURCES_GRAPHICS_DIR}/ShaderDX.cpp ${SOURCES_GRAPHICS_DIR}/ProgramDX.h ${SOURCES_GRAPHICS_DIR}/ProgramDX.cpp + ${SOURCES_GRAPHICS_DIR}/ProgramBindingsDX.h + ${SOURCES_GRAPHICS_DIR}/ProgramBindingsDX.cpp + ${SOURCES_GRAPHICS_DIR}/RenderContextDX.h + ${SOURCES_GRAPHICS_DIR}/RenderContextDX.cpp ${SOURCES_GRAPHICS_DIR}/RenderStateDX.h ${SOURCES_GRAPHICS_DIR}/RenderStateDX.cpp ${SOURCES_GRAPHICS_DIR}/ResourceDX.h @@ -33,6 +39,10 @@ if (WIN32) ${SOURCES_GRAPHICS_DIR}/RenderPassDX.cpp ${SOURCES_GRAPHICS_DIR}/CommandQueueDX.h ${SOURCES_GRAPHICS_DIR}/CommandQueueDX.cpp + ${SOURCES_GRAPHICS_DIR}/CommandListDX.h + ${SOURCES_GRAPHICS_DIR}/CommandListDX.hpp + ${SOURCES_GRAPHICS_DIR}/BlitCommandListDX.h + ${SOURCES_GRAPHICS_DIR}/BlitCommandListDX.cpp ${SOURCES_GRAPHICS_DIR}/RenderCommandListDX.h ${SOURCES_GRAPHICS_DIR}/RenderCommandListDX.cpp ${SOURCES_GRAPHICS_DIR}/ParallelRenderCommandListDX.h @@ -42,10 +52,10 @@ if (WIN32) set(PLATFORM_LIBRARIES D3DX12 DirectXTex + D3DCompilerToDXC d3d12 dxgi dxguid - d3dcompiler Shcore ) @@ -61,18 +71,26 @@ elseif(APPLE) ${SOURCES_GRAPHICS_DIR}/TypesMT.mm ${SOURCES_GRAPHICS_DIR}/DeviceMT.hh ${SOURCES_GRAPHICS_DIR}/DeviceMT.mm - ${SOURCES_GRAPHICS_DIR}/ContextMT.hh - ${SOURCES_GRAPHICS_DIR}/ContextMT.mm + ${SOURCES_GRAPHICS_DIR}/FenceMT.hh + ${SOURCES_GRAPHICS_DIR}/FenceMT.mm + ${SOURCES_GRAPHICS_DIR}/ContextMT.h + ${SOURCES_GRAPHICS_DIR}/ContextMT.hpp + ${SOURCES_GRAPHICS_DIR}/RenderContextMT.hh + ${SOURCES_GRAPHICS_DIR}/RenderContextMT.mm ${SOURCES_GRAPHICS_DIR}/ShaderMT.hh ${SOURCES_GRAPHICS_DIR}/ShaderMT.mm ${SOURCES_GRAPHICS_DIR}/ProgramMT.hh ${SOURCES_GRAPHICS_DIR}/ProgramMT.mm + ${SOURCES_GRAPHICS_DIR}/ProgramLibraryMT.hh + ${SOURCES_GRAPHICS_DIR}/ProgramLibraryMT.mm + ${SOURCES_GRAPHICS_DIR}/ProgramBindingsMT.hh + ${SOURCES_GRAPHICS_DIR}/ProgramBindingsMT.mm ${SOURCES_GRAPHICS_DIR}/RenderStateMT.hh ${SOURCES_GRAPHICS_DIR}/RenderStateMT.mm ${SOURCES_GRAPHICS_DIR}/ResourceMT.hh ${SOURCES_GRAPHICS_DIR}/ResourceMT.mm ${SOURCES_GRAPHICS_DIR}/DescriptorHeapMT.hh - ${SOURCES_GRAPHICS_DIR}/DescriptorHeapMT.mm + ${SOURCES_GRAPHICS_DIR}/DescriptorHeapMT.mm ${SOURCES_GRAPHICS_DIR}/BufferMT.hh ${SOURCES_GRAPHICS_DIR}/BufferMT.mm ${SOURCES_GRAPHICS_DIR}/TextureMT.hh @@ -83,6 +101,8 @@ elseif(APPLE) ${SOURCES_GRAPHICS_DIR}/RenderPassMT.mm ${SOURCES_GRAPHICS_DIR}/CommandQueueMT.hh ${SOURCES_GRAPHICS_DIR}/CommandQueueMT.mm + ${SOURCES_GRAPHICS_DIR}/BlitCommandListMT.hh + ${SOURCES_GRAPHICS_DIR}/BlitCommandListMT.mm ${SOURCES_GRAPHICS_DIR}/RenderCommandListMT.hh ${SOURCES_GRAPHICS_DIR}/RenderCommandListMT.mm ${SOURCES_GRAPHICS_DIR}/ParallelRenderCommandListMT.hh @@ -107,12 +127,18 @@ else() # Linux ${SOURCES_GRAPHICS_DIR}/TypesVK.cpp ${SOURCES_GRAPHICS_DIR}/DeviceVK.h ${SOURCES_GRAPHICS_DIR}/DeviceVK.cpp + ${SOURCES_GRAPHICS_DIR}/FenceVK.h + ${SOURCES_GRAPHICS_DIR}/FenceVK.cpp ${SOURCES_GRAPHICS_DIR}/ContextVK.h - ${SOURCES_GRAPHICS_DIR}/ContextVK.cpp + ${SOURCES_GRAPHICS_DIR}/ContextVK.hpp ${SOURCES_GRAPHICS_DIR}/ShaderVK.h ${SOURCES_GRAPHICS_DIR}/ShaderVK.cpp ${SOURCES_GRAPHICS_DIR}/ProgramVK.h ${SOURCES_GRAPHICS_DIR}/ProgramVK.cpp + ${SOURCES_GRAPHICS_DIR}/ProgramBindingsVK.h + ${SOURCES_GRAPHICS_DIR}/ProgramBindingsVK.cpp + ${SOURCES_GRAPHICS_DIR}/RenderContextVK.h + ${SOURCES_GRAPHICS_DIR}/RenderContextVK.cpp ${SOURCES_GRAPHICS_DIR}/RenderStateVK.h ${SOURCES_GRAPHICS_DIR}/RenderStateVK.cpp ${SOURCES_GRAPHICS_DIR}/ResourceVK.h @@ -129,6 +155,8 @@ else() # Linux ${SOURCES_GRAPHICS_DIR}/RenderPassVK.cpp ${SOURCES_GRAPHICS_DIR}/CommandQueueVK.h ${SOURCES_GRAPHICS_DIR}/CommandQueueVK.cpp + ${SOURCES_GRAPHICS_DIR}/BlitCommandListVK.h + ${SOURCES_GRAPHICS_DIR}/BlitCommandListVK.cpp ${SOURCES_GRAPHICS_DIR}/RenderCommandListVK.h ${SOURCES_GRAPHICS_DIR}/RenderCommandListVK.cpp ${SOURCES_GRAPHICS_DIR}/ParallelRenderCommandListVK.h @@ -138,20 +166,24 @@ else() # Linux endif() set(LIBRARIES ${PLATFORM_LIBRARIES} + MethaneCommonPrimitives MethaneDataPrimitives MethaneDataRangeSet MethanePlatformUtils MethanePlatformAppView MethaneGraphicsHelpers - MethaneDataInstrumentation + MethaneInstrumentation ) set(HEADERS ${INCLUDE_DIR}/Types.h ${INCLUDE_DIR}/Device.h ${INCLUDE_DIR}/Context.h + ${INCLUDE_DIR}/RenderContext.h + ${INCLUDE_DIR}/Fence.h ${INCLUDE_DIR}/Shader.h ${INCLUDE_DIR}/Program.h + ${INCLUDE_DIR}/ProgramBindings.h ${INCLUDE_DIR}/RenderState.h ${INCLUDE_DIR}/Resource.h ${INCLUDE_DIR}/Buffer.h @@ -160,6 +192,7 @@ set(HEADERS ${INCLUDE_DIR}/RenderPass.h ${INCLUDE_DIR}/CommandQueue.h ${INCLUDE_DIR}/CommandList.h + ${INCLUDE_DIR}/BlitCommandList.h ${INCLUDE_DIR}/RenderCommandList.h ${INCLUDE_DIR}/ParallelRenderCommandList.h ) @@ -168,6 +201,7 @@ set(SOURCES ${PLATFORM_SOURCES} # Native alias headers ${SOURCES_DIR}/Native/ContextNT.h + ${SOURCES_DIR}/Native/RenderContextNT.h ${SOURCES_DIR}/Native/ShaderNT.h ${SOURCES_DIR}/Native/ProgramNT.h ${SOURCES_DIR}/Native/RenderStateNT.h @@ -186,10 +220,16 @@ set(SOURCES ${PLATFORM_SOURCES} ${SOURCES_DIR}/DeviceBase.cpp ${SOURCES_DIR}/ContextBase.h ${SOURCES_DIR}/ContextBase.cpp + ${SOURCES_DIR}/RenderContextBase.h + ${SOURCES_DIR}/RenderContextBase.cpp + ${SOURCES_DIR}/FenceBase.h + ${SOURCES_DIR}/FenceBase.cpp ${SOURCES_DIR}/ShaderBase.h ${SOURCES_DIR}/ShaderBase.cpp ${SOURCES_DIR}/ProgramBase.h ${SOURCES_DIR}/ProgramBase.cpp + ${SOURCES_DIR}/ProgramBindingsBase.h + ${SOURCES_DIR}/ProgramBindingsBase.cpp ${SOURCES_DIR}/RenderStateBase.h ${SOURCES_DIR}/RenderStateBase.cpp ${SOURCES_DIR}/ResourceBase.h @@ -206,6 +246,7 @@ set(SOURCES ${PLATFORM_SOURCES} ${SOURCES_DIR}/CommandQueueBase.cpp ${SOURCES_DIR}/CommandListBase.h ${SOURCES_DIR}/CommandListBase.cpp + ${SOURCES_DIR}/CommandListState.cpp ${SOURCES_DIR}/RenderCommandListBase.h ${SOURCES_DIR}/RenderCommandListBase.cpp ${SOURCES_DIR}/ParallelRenderCommandListBase.h @@ -217,7 +258,7 @@ set(SOURCES ${PLATFORM_SOURCES} ${SOURCES_DIR}/ResourceManager.h ${SOURCES_DIR}/ResourceManager.cpp ${SOURCES_DIR}/Types.cpp -) + Include/Methane/Graphics/Fence.h) add_library(${TARGET} STATIC ${HEADERS} @@ -246,6 +287,7 @@ set_target_properties(${TARGET} PROPERTIES FOLDER Modules/Graphics PUBLIC_HEADER "${HEADERS}" + PREREQUISITE_MODULES "DirectXCompiler" ) install(TARGETS ${TARGET} diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/BlitCommandList.h b/Modules/Graphics/Core/Include/Methane/Graphics/BlitCommandList.h new file mode 100644 index 000000000..4d50fa3c7 --- /dev/null +++ b/Modules/Graphics/Core/Include/Methane/Graphics/BlitCommandList.h @@ -0,0 +1,39 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/BlitCommandList.h +Methane blit command list interface. + +******************************************************************************/ + +#pragma once + +#include "CommandList.h" + +#include + +namespace Methane::Graphics +{ + +struct BlitCommandList : virtual CommandList +{ + // Create BlitCommandList instance + static Ptr Create(CommandQueue& command_queue); +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/Buffer.h b/Modules/Graphics/Core/Include/Methane/Graphics/Buffer.h index 13ce532c0..78c6db151 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/Buffer.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/Buffer.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,18 +25,13 @@ Methane buffer interface: GPU memory buffer resource. #include "Resource.h" -#include - namespace Methane::Graphics { +struct Context; + struct Buffer : virtual Resource { - using Ptr = std::shared_ptr; - using WeakPtr = std::weak_ptr; - using Ref = std::reference_wrapper; - using Refs = std::vector; - enum class Type { Data = 0, @@ -53,11 +48,11 @@ struct Buffer : virtual Resource }; // Create Buffer instance - static Ptr CreateVertexBuffer(Context& context, Data::Size size, Data::Size stride); - static Ptr CreateIndexBuffer(Context& context, Data::Size size, PixelFormat format); - static Ptr CreateConstantBuffer(Context& context, Data::Size size, bool addressable = false, const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); + static Ptr CreateVertexBuffer(Context& context, Data::Size size, Data::Size stride); + static Ptr CreateIndexBuffer(Context& context, Data::Size size, PixelFormat format); + static Ptr CreateConstantBuffer(Context& context, Data::Size size, bool addressable = false, const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); - // Auxillary functions + // Auxiliary functions static Data::Size GetAlignedBufferSize(Data::Size size) noexcept; static std::string GetBufferTypeName(Type type) noexcept; diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/CommandList.h b/Modules/Graphics/Core/Include/Methane/Graphics/CommandList.h index 8bb34dcc6..40b2824a5 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/CommandList.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/CommandList.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,14 +24,10 @@ to create instance refer to RenderCommandList, etc. for specific derived interfa #pragma once -#include "Types.h" #include "Object.h" -#include "Resource.h" -#include "Program.h" +#include "ProgramBindings.h" -#include #include -#include namespace Methane::Graphics { @@ -40,23 +36,21 @@ struct CommandQueue; struct CommandList : virtual Object { - using Ptr = std::shared_ptr; - using Ref = std::reference_wrapper; - using Refs = std::vector; - enum class Type : uint32_t { - RenderCommandList = 0u, - ParallelRenderCommandList, + Blit = 0u, + Render, + ParallelRender, }; // CommandList interface virtual Type GetType() const = 0; virtual void PushDebugGroup(const std::string& name) = 0; virtual void PopDebugGroup() = 0; - virtual void SetResourceBindings(Program::ResourceBindings& resource_bindings, - Program::ResourceBindings::ApplyBehavior::Mask apply_behavior = Program::ResourceBindings::ApplyBehavior::AllIncremental) = 0; - virtual void Commit(bool present_drawable) = 0; + virtual void Reset(const std::string& debug_group = "") = 0; + virtual void SetProgramBindings(ProgramBindings& program_bindings, + ProgramBindings::ApplyBehavior::Mask apply_behavior = ProgramBindings::ApplyBehavior::AllIncremental) = 0; + virtual void Commit() = 0; virtual CommandQueue& GetCommandQueue() = 0; virtual ~CommandList() = default; diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/CommandQueue.h b/Modules/Graphics/Core/Include/Methane/Graphics/CommandQueue.h index 557540e63..ab47dcbf8 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/CommandQueue.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/CommandQueue.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,24 +25,20 @@ Methane command queue interface: queues are used to execute command lists. #include "Object.h" #include "CommandList.h" +#include "Context.h" -#include +#include namespace Methane::Graphics { -struct Context; - struct CommandQueue : virtual Object { - using Ptr = std::shared_ptr; - using WeakPtr = std::weak_ptr; - // Create CommandQueue instance - static Ptr Create(Context& context); + static Ptr Create(Context& context); // CommandQueue interface - virtual void Execute(const CommandList::Refs& command_lists) = 0; + virtual void Execute(const Refs& command_lists) = 0; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/Context.h b/Modules/Graphics/Core/Include/Methane/Graphics/Context.h index b9e94a991..a9da40453 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/Context.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/Context.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,8 +17,7 @@ limitations under the License. ******************************************************************************* FILE: Methane/Graphics/Context.h -Methane context interface: represents graphics device and swap chain, -provides basic multi-frame rendering synchronization and frame presenting APIs. +Methane base context interface: wraps graphics device used for GPU interaction. ******************************************************************************/ @@ -27,35 +26,20 @@ provides basic multi-frame rendering synchronization and frame presenting APIs. #include "Object.h" #include "Types.h" -#include -#include - -#include -#include +#include namespace Methane::Graphics { -class FpsCounter; struct Device; struct CommandQueue; -struct RenderCommandList; +struct BlitCommandList; struct Context : virtual Object { - using Ptr = std::shared_ptr; - - struct Settings + enum class Type { - FrameSize frame_size; - PixelFormat color_format = PixelFormat::BGRA8Unorm; - PixelFormat depth_stencil_format = PixelFormat::Unknown; - std::optional clear_color; - std::optional clear_depth_stencil; - uint32_t frame_buffers_count = 3; - bool vsync_enabled = true; - bool is_full_screen = false; - uint32_t unsync_max_fps = 1000; // MacOS only + Render, }; enum class WaitFor @@ -64,45 +48,28 @@ struct Context : virtual Object FramePresented, ResourcesUploaded }; - + struct Callback { - using Ref = std::reference_wrapper; - virtual void OnContextReleased() = 0; virtual void OnContextInitialized() = 0; - + virtual ~Callback() = default; }; - // Create Context instance - static Ptr Create(const Platform::AppEnvironment& env, Device& device, const Settings& settings); - // Context interface + virtual Type GetType() const = 0; virtual void CompleteInitialization() = 0; - virtual bool ReadyToRender() const = 0; virtual void WaitForGpu(WaitFor wait_for) = 0; - virtual void Resize(const FrameSize& frame_size) = 0; virtual void Reset(Device& device) = 0; virtual void Reset() = 0; - virtual void Present() = 0; - + virtual void AddCallback(Callback& callback) = 0; virtual void RemoveCallback(Callback& callback) = 0; - virtual Platform::AppView GetAppView() const = 0; - virtual Device& GetDevice() = 0; - virtual CommandQueue& GetRenderCommandQueue() = 0; - virtual CommandQueue& GetUploadCommandQueue() = 0; - virtual RenderCommandList& GetUploadCommandList() = 0; - virtual const Settings& GetSettings() const = 0; - virtual uint32_t GetFrameBufferIndex() const = 0; - virtual float GetContentScalingFactor() const = 0; - virtual const FpsCounter& GetFpsCounter() const = 0; - - virtual bool SetVSyncEnabled(bool vsync_enabled) = 0; - virtual bool SetFrameBuffersCount(uint32_t frame_buffers_count) = 0; - virtual bool SetFullScreen(bool is_full_screen) = 0; + virtual Device& GetDevice() = 0; + virtual CommandQueue& GetUploadCommandQueue() = 0; + virtual BlitCommandList& GetUploadCommandList() = 0; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/Core.h b/Modules/Graphics/Core/Include/Methane/Graphics/Core.h index 3a03018b9..5a12608c4 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/Core.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/Core.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,9 +25,10 @@ Methane graphics core interfaces: all headers under one umbrella. #include "Types.h" #include "Device.h" -#include "Context.h" +#include "RenderContext.h" #include "Shader.h" #include "Program.h" +#include "ProgramBindings.h" #include "RenderState.h" #include "RenderPass.h" #include "Resource.h" diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/Device.h b/Modules/Graphics/Core/Include/Methane/Graphics/Device.h index 027617582..e7296df51 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/Device.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/Device.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,9 +26,9 @@ is used to create graphics context for rendering. #include "Object.h" -#include +#include + #include -#include #include namespace Methane::Graphics @@ -36,8 +36,6 @@ namespace Methane::Graphics struct Device : virtual Object { - using Ptr = std::shared_ptr; - enum class Notification : uint32_t { RemoveRequested = 0, @@ -75,17 +73,15 @@ struct Device : virtual Object virtual std::string ToString() const noexcept = 0; }; -using Devices = std::vector; - struct System { static System& Get(); virtual void CheckForChanges() = 0; - virtual const Devices& UpdateGpuDevices(Device::Feature::Mask supported_features = Device::Feature::Value::All) = 0; - virtual const Devices& GetGpuDevices() const = 0; - virtual Device::Ptr GetNextGpuDevice(const Device& device) const = 0; - virtual Device::Ptr GetSoftwareGpuDevice() const = 0; + virtual const Ptrs& UpdateGpuDevices(Device::Feature::Mask supported_features = Device::Feature::Value::All) = 0; + virtual const Ptrs& GetGpuDevices() const = 0; + virtual Ptr GetNextGpuDevice(const Device& device) const = 0; + virtual Ptr GetSoftwareGpuDevice() const = 0; virtual Device::Feature::Mask GetGpuSupportedFeatures() const = 0; virtual std::string ToString() const noexcept = 0; diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/Fence.h b/Modules/Graphics/Core/Include/Methane/Graphics/Fence.h new file mode 100644 index 000000000..7a87a7932 --- /dev/null +++ b/Modules/Graphics/Core/Include/Methane/Graphics/Fence.h @@ -0,0 +1,45 @@ +/****************************************************************************** + +Copyright 2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Fence.h +Methane fence interface used for CPU-GPU synchronization. + +******************************************************************************/ + +#pragma once + +#include "Object.h" + +#include + +namespace Methane::Graphics +{ + +struct CommandQueue; + +struct Fence : virtual Object +{ + static UniquePtr Create(CommandQueue& command_queue); + + // Fence interface + virtual void Signal() = 0; + virtual void Wait() = 0; + virtual void Flush() = 0; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/Object.h b/Modules/Graphics/Core/Include/Methane/Graphics/Object.h index fd319717a..b0fb1aebd 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/Object.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/Object.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/ParallelRenderCommandList.h b/Modules/Graphics/Core/Include/Methane/Graphics/ParallelRenderCommandList.h index 75f68959c..ec7fa8c40 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/ParallelRenderCommandList.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/ParallelRenderCommandList.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,6 +26,8 @@ for multi-threaded rendering in the single render pass. #include "RenderCommandList.h" +#include + namespace Methane::Graphics { @@ -34,15 +36,15 @@ struct RenderPass; struct ParallelRenderCommandList : virtual CommandList { - using Ptr = std::shared_ptr; - // Create ParallelRenderCommandList instance - static Ptr Create(CommandQueue& command_queue, RenderPass& render_pass); - + static Ptr Create(CommandQueue& command_queue, RenderPass& render_pass); + // ParallelRenderCommandList interface - virtual void Reset(const RenderState::Ptr& sp_render_state = RenderState::Ptr(), const std::string& debug_group = "") = 0; + virtual void Reset(const Ptr& sp_render_state = Ptr(), const std::string& debug_group = "") = 0; virtual void SetParallelCommandListsCount(uint32_t count) = 0; - virtual const RenderCommandList::Ptrs& GetParallelCommandLists() const = 0; + virtual const Ptrs& GetParallelCommandLists() const = 0; + + using CommandList::Reset; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/Program.h b/Modules/Graphics/Core/Include/Methane/Graphics/Program.h index b528b9b6c..a7a341e1d 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/Program.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/Program.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,7 +28,8 @@ pipeline via state object and used to create resource binding objects. #include "Object.h" #include "Types.h" -#include +#include + #include #include #include @@ -44,8 +45,6 @@ struct CommandList; struct Program : virtual Object { - using Ptr = std::shared_ptr; - struct InputBufferLayout { enum class StepType @@ -54,29 +53,38 @@ struct Program : virtual Object PerVertex, PerInstance, }; - - struct Argument - { - std::string name; - std::string semantic; - }; - - using Arguments = std::vector; - - Arguments arguments; - StepType step_type = StepType::PerVertex; - uint32_t step_rate = 1; + + using ArgumentSemantics = std::vector; + + ArgumentSemantics argument_semantics; + StepType step_type = StepType::PerVertex; + uint32_t step_rate = 1; }; using InputBufferLayouts = std::vector; struct Argument { + struct Modifiers + { + using Mask = uint32_t; + enum Value : Mask + { + None = 0u, + Constant = 1u << 0u, + Addressable = 1u << 1u, + All = ~0u, + }; + + Modifiers() = delete; + }; + const Shader::Type shader_type; - const std::string argument_name; + const std::string name; const size_t hash; Argument(Shader::Type shader_type, std::string argument_name); + Argument(const Argument& argument) = default; bool operator==(const Argument& other) const; @@ -86,59 +94,43 @@ struct Program : virtual Object }; }; - using Arguments = std::unordered_set; - using ResourceBindingByArgument = std::unordered_map; + using Arguments = std::unordered_set; - struct ResourceBindings + struct ArgumentDesc : Argument { - using Ptr = std::shared_ptr; - using WeakPtr = std::weak_ptr; - using ResourceLocationsByArgument = std::unordered_map; - - struct ApplyBehavior - { - using Mask = uint32_t; - enum Value : Mask - { - Indifferent = 0u, // All bindings will be applied indifferently of the previous binding values - ConstantOnce = 1u << 0, // Constant program arguments will be applied only once for each command list - ChangesOnly = 1u << 1, // Only changed program argument values will be applied in command sequence - StateBarriers = 1u << 2, // Resource state barriers will be automatically evaluated and set for command list - AllIncremental = ~0u // All binding values will be applied incrementally along with resource state barriers - }; - - ApplyBehavior() = delete; - }; - - // Create ResourceBindings instance - static Ptr Create(const Program::Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument); - static Ptr CreateCopy(const ResourceBindings& other_resource_bingings, const ResourceLocationsByArgument& replace_resource_locations_by_argument = {}); + const Modifiers::Mask modifiers; - // ResourceBindings interface - virtual const Shader::ResourceBinding::Ptr& Get(const Argument& shader_argument) const = 0; - virtual void Apply(CommandList& command_list, ApplyBehavior::Mask apply_behavior = ApplyBehavior::AllIncremental) const = 0; + ArgumentDesc(Shader::Type shader_type, std::string argument_name, + Modifiers::Mask modifiers_mask = Modifiers::None); + ArgumentDesc(const Argument& argument, + Modifiers::Mask modifiers_mask = Modifiers::None); + ArgumentDesc(const ArgumentDesc& argument_desc) = default; - virtual ~ResourceBindings() = default; + inline bool IsConstant() const { return modifiers & Modifiers::Constant; } + inline bool IsAddressable() const { return modifiers & Modifiers::Addressable; } }; + using ArgumentDescriptions = std::unordered_set; + static ArgumentDescriptions::const_iterator FindArgumentDescription(const ArgumentDescriptions& argument_descriptions, const Argument& argument); + using Shaders = Ptrs; + // Program settings struct Settings { - Shaders shaders; - InputBufferLayouts input_buffer_layouts; - std::set constant_argument_names; - std::set addressable_argument_names; - std::vector color_formats; - PixelFormat depth_format = PixelFormat::Unknown; + Shaders shaders; + InputBufferLayouts input_buffer_layouts; + ArgumentDescriptions argument_descriptions; + PixelFormats color_formats; + PixelFormat depth_format = PixelFormat::Unknown; }; // Create Program instance - static Ptr Create(Context& context, const Settings& settings); + static Ptr Create(Context& context, const Settings& settings); // Program interface virtual const Settings& GetSettings() const = 0; virtual const Shader::Types& GetShaderTypes() const = 0; - virtual const Shader::Ptr& GetShader(Shader::Type shader_type) const = 0; + virtual const Ptr& GetShader(Shader::Type shader_type) const = 0; virtual ~Program() = default; }; diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/ProgramBindings.h b/Modules/Graphics/Core/Include/Methane/Graphics/ProgramBindings.h new file mode 100644 index 000000000..1ed284da4 --- /dev/null +++ b/Modules/Graphics/Core/Include/Methane/Graphics/ProgramBindings.h @@ -0,0 +1,86 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/ProgramBindings.h +Methane program bindings interface for resources binding to program arguments. + +******************************************************************************/ + +#pragma once + +#include "Program.h" +#include "Resource.h" + +#include + +#include +#include + +namespace Methane::Graphics +{ + +struct ProgramBindings +{ + struct ArgumentBinding + { + // ArgumentBinding settings + struct Settings + { + Program::ArgumentDesc argument; + Resource::Type resource_type; + uint32_t resource_count = 1; + }; + + // ArgumentBinding interface + virtual const Settings& GetSettings() const noexcept = 0; + virtual const Resource::Locations& GetResourceLocations() const noexcept = 0; + virtual void SetResourceLocations(const Resource::Locations& resource_locations) = 0; + + virtual ~ArgumentBinding() = default; + }; + + using ArgumentBindings = std::unordered_map, Program::Argument::Hash>; + + struct ApplyBehavior + { + using Mask = uint32_t; + enum Value : Mask + { + Indifferent = 0u, // All bindings will be applied indifferently of the previous binding values + ConstantOnce = 1u << 0, // Constant program arguments will be applied only once for each command list + ChangesOnly = 1u << 1, // Only changed program argument values will be applied in command sequence + StateBarriers = 1u << 2, // Resource state barriers will be automatically evaluated and set for command list + AllIncremental = ~0u // All binding values will be applied incrementally along with resource state barriers + }; + + ApplyBehavior() = delete; + }; + + using ResourceLocationsByArgument = std::unordered_map; + + // Create ProgramBindings instance + static Ptr Create(const Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument); + static Ptr CreateCopy(const ProgramBindings& other_program_bindings, const ResourceLocationsByArgument& replace_resource_locations_by_argument = {}); + + // ProgramBindings interface + virtual const Ptr& Get(const Program::Argument& shader_argument) const = 0; + + virtual ~ProgramBindings() = default; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/RenderCommandList.h b/Modules/Graphics/Core/Include/Methane/Graphics/RenderCommandList.h index c552af4d7..deffa4ed6 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/RenderCommandList.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/RenderCommandList.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -27,6 +27,8 @@ Methane render command list interface. #include "Buffer.h" #include "RenderState.h" +#include + namespace Methane::Graphics { @@ -35,10 +37,6 @@ struct ParallelRenderCommandList; struct RenderCommandList : virtual CommandList { - using Ptr = std::shared_ptr; - using Ptrs = std::vector; - using ConstPtrs = std::vector; - enum class Primitive { Point, @@ -49,18 +47,20 @@ struct RenderCommandList : virtual CommandList }; // Create RenderCommandList instance - static Ptr Create(CommandQueue& command_queue, RenderPass& render_pass); - static Ptr Create(ParallelRenderCommandList& parallel_command_list); - + static Ptr Create(CommandQueue& command_queue, RenderPass& render_pass); + static Ptr Create(ParallelRenderCommandList& parallel_command_list); + // RenderCommandList interface - virtual void Reset(const RenderState::Ptr& sp_render_state = RenderState::Ptr(), const std::string& debug_group = "") = 0; + virtual void Reset(const Ptr& sp_render_state, const std::string& debug_group = "") = 0; virtual void SetState(RenderState& render_state, RenderState::Group::Mask state_groups = RenderState::Group::All) = 0; - virtual void SetVertexBuffers(const Buffer::Refs& vertex_buffers) = 0; + virtual void SetVertexBuffers(const Refs& vertex_buffers) = 0; virtual void DrawIndexed(Primitive primitive, Buffer& index_buffer, uint32_t index_count = 0, uint32_t start_index = 0, uint32_t start_vertex = 0, uint32_t instance_count = 1, uint32_t start_instance = 0) = 0; virtual void Draw(Primitive primitive, uint32_t vertex_count, uint32_t start_vertex = 0, uint32_t instance_count = 1, uint32_t start_instance = 0) = 0; + + using CommandList::Reset; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/RenderContext.h b/Modules/Graphics/Core/Include/Methane/Graphics/RenderContext.h new file mode 100644 index 000000000..cc7b136e0 --- /dev/null +++ b/Modules/Graphics/Core/Include/Methane/Graphics/RenderContext.h @@ -0,0 +1,75 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/RenderContext.h +Methane render context interface: represents graphics device and swap chain, +provides basic multi-frame rendering synchronization and frame presenting APIs. + +******************************************************************************/ + +#pragma once + +#include "Context.h" + +#include +#include + +#include + +namespace Methane::Graphics +{ + +class FpsCounter; +struct RenderCommandList; + +struct RenderContext : virtual Context +{ + struct Settings + { + FrameSize frame_size; + PixelFormat color_format = PixelFormat::BGRA8Unorm; + PixelFormat depth_stencil_format = PixelFormat::Unknown; + std::optional clear_color; + std::optional clear_depth_stencil; + uint32_t frame_buffers_count = 3; + bool vsync_enabled = true; + bool is_full_screen = false; + uint32_t unsync_max_fps = 1000; // MacOS only + }; + + // Create RenderContext instance + static Ptr Create(const Platform::AppEnvironment& env, Device& device, const Settings& settings); + + // RenderContext interface + virtual bool ReadyToRender() const = 0; + virtual void Resize(const FrameSize& frame_size) = 0; + virtual void Present() = 0; + + virtual Platform::AppView GetAppView() const = 0; + virtual CommandQueue& GetRenderCommandQueue() = 0; + virtual const Settings& GetSettings() const = 0; + virtual uint32_t GetFrameBufferIndex() const = 0; + virtual float GetContentScalingFactor() const = 0; + virtual const FpsCounter& GetFpsCounter() const = 0; + + virtual bool SetVSyncEnabled(bool vsync_enabled) = 0; + virtual bool SetFrameBuffersCount(uint32_t frame_buffers_count) = 0; + virtual bool SetFullScreen(bool is_full_screen) = 0; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/RenderPass.h b/Modules/Graphics/Core/Include/Methane/Graphics/RenderPass.h index 3990d5e49..ec1317851 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/RenderPass.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/RenderPass.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,19 +26,17 @@ Methane render pass interface: specifies output of the graphics pipeline. #include "Types.h" #include "Texture.h" -#include +#include + #include namespace Methane::Graphics { -struct Context; -struct Resource; +struct RenderContext; struct RenderPass { - using Ptr = std::shared_ptr; - struct Attachment { enum class LoadAction : uint32_t @@ -55,7 +53,7 @@ struct RenderPass Resolve, }; - Texture::WeakPtr wp_texture; + WeakPtr wp_texture; uint32_t level = 0u; uint32_t slice = 0u; uint32_t depth_plane = 0u; @@ -115,8 +113,6 @@ struct RenderPass struct Settings { - using Ptr = std::unique_ptr; - ColorAttachments color_attachments; DepthAttachment depth_attachment; StencilAttachment stencil_attachment; @@ -127,7 +123,7 @@ struct RenderPass }; // Create RenderPass instance - static Ptr Create(Context& context, const Settings& settings); + static Ptr Create(RenderContext& context, const Settings& settings); // RenderPass interface virtual void Update(const Settings& settings) = 0; diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/RenderState.h b/Modules/Graphics/Core/Include/Methane/Graphics/RenderState.h index 19c23ca0f..1c4769450 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/RenderState.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/RenderState.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -27,21 +27,17 @@ Methane render state interface: specifies configuration of the graphics pipeline #include "Program.h" #include "Types.h" -#include -#include +#include namespace Methane::Graphics { -struct Context; +struct RenderContext; struct RenderCommandList; struct RenderState : virtual Object { public: - using Ptr = std::shared_ptr; - using WeakPtr = std::weak_ptr; - struct Rasterizer { enum class CullMode : uint32_t @@ -210,7 +206,7 @@ struct RenderState : virtual Object // NOTE: members are ordered by the usage frequency, // for convenient setup with initializer lists // (default states may be skipped at initialization) - Program::Ptr sp_program; + Ptr sp_program; Viewports viewports; ScissorRects scissor_rects; Rasterizer rasterizer; @@ -223,7 +219,7 @@ struct RenderState : virtual Object }; // Create RenderState instance - static Ptr Create(Context& context, const Settings& state_settings); + static Ptr Create(RenderContext& context, const Settings& state_settings); // RenderState interface virtual const Settings& GetSettings() const = 0; diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/Resource.h b/Modules/Graphics/Core/Include/Methane/Graphics/Resource.h index 36e313cfe..f423c1aa9 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/Resource.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/Resource.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,7 +26,8 @@ Methane resource interface: base class of all GPU resources. #include "Object.h" #include "Types.h" -#include +#include + #include #include #include @@ -35,16 +36,10 @@ Methane resource interface: base class of all GPU resources. namespace Methane::Graphics { -struct Context; class DescriptorHeap; struct Resource : virtual Object { - using Ptr = std::shared_ptr; - using WeakPtr = std::weak_ptr; - using Ref = std::reference_wrapper; - using Refs = std::vector; - enum class Type : uint32_t { Buffer = 0u, @@ -82,9 +77,9 @@ struct Resource : virtual Object struct Descriptor { DescriptorHeap& heap; - int32_t index; + Data::Index index; - Descriptor(DescriptorHeap& in_heap, int32_t in_index = -1); + Descriptor(DescriptorHeap& in_heap, Data::Index in_index); }; using DescriptorByUsage = std::map; @@ -92,17 +87,17 @@ struct Resource : virtual Object class Location { public: - Location(Ptr sp_resource, Data::Size offset = 0u); + Location(Ptr sp_resource, Data::Size offset = 0u); bool operator==(const Location& other) const; - const Ptr& GetResourcePtr() const { return m_sp_resource; } - Resource& GetResource() const { return *m_sp_resource; } - Data::Size GetOffset() const { return m_offset; } + const Ptr& GetResourcePtr() const { return m_sp_resource; } + Resource& GetResource() const { return *m_sp_resource; } + Data::Size GetOffset() const { return m_offset; } private: - Ptr m_sp_resource; - Data::Size m_offset; + Ptr m_sp_resource; + Data::Size m_offset; }; using Locations = std::vector; @@ -145,10 +140,9 @@ struct Resource : virtual Object using SubResources = std::vector; - // Auxillary functions + // Auxiliary functions static std::string GetTypeName(Type type) noexcept; - // Resource interface virtual void SetData(const SubResources& sub_resources) = 0; virtual Data::Size GetDataSize() const = 0; diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/Sampler.h b/Modules/Graphics/Core/Include/Methane/Graphics/Sampler.h index 2bc1459c8..12a66a0ad 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/Sampler.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/Sampler.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,7 +26,8 @@ Methane sampler interface: GPU resource for texture sampling. #include "Resource.h" #include "Types.h" -#include +#include + #include #include @@ -37,9 +38,6 @@ struct Context; struct Sampler : virtual Resource { - using Ptr = std::shared_ptr; - using WeakPtr = std::weak_ptr; - struct Filter { enum class MinMag : uint32_t @@ -85,9 +83,7 @@ struct Sampler : virtual Resource struct LevelOfDetail { - LevelOfDetail(float in_bias = 0.f, float in_min = 0.f, float in_max = std::numeric_limits::max()) - : min(in_min), max(in_max), bias(in_bias) - { } + LevelOfDetail(float in_bias = 0.f, float in_min = 0.f, float in_max = std::numeric_limits::max()); float min = 0.f; float max = std::numeric_limits::max(); @@ -103,12 +99,13 @@ struct Sampler : virtual Resource struct Settings { - Settings(const Filter& in_filter, const Address& in_address, const LevelOfDetail& in_lod = LevelOfDetail(), uint32_t in_max_anisotropy = 1, - BorderColor in_border_color = BorderColor::TransparentBlack, Compare in_compare_function = Compare::Never) - : filter(in_filter), address(in_address), lod(in_lod), max_anisotropy(in_max_anisotropy) - , border_color(in_border_color), compare_function(in_compare_function) - { } - + Settings(const Filter& in_filter, + const Address& in_address, + const LevelOfDetail& in_lod = LevelOfDetail(), + uint32_t in_max_anisotropy = 1, + BorderColor in_border_color = BorderColor::TransparentBlack, + Compare in_compare_function = Compare::Never); + Filter filter; Address address; LevelOfDetail lod; @@ -118,7 +115,7 @@ struct Sampler : virtual Resource }; // Create Sampler instance - static Ptr Create(Context& context, const Settings& state_settings, const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); + static Ptr Create(Context& context, const Settings& state_settings, const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); // Sampler interface virtual const Settings& GetSettings() const = 0; diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/Shader.h b/Modules/Graphics/Core/Include/Methane/Graphics/Shader.h index e7659ce12..8a57400a1 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/Shader.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/Shader.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,11 +23,9 @@ Methane shader interface: defines programmable stage of the graphics pipeline. #pragma once -#include "Resource.h" +#include -#include #include -#include #include #include @@ -43,9 +41,6 @@ struct Context; struct Shader { - using Ptr = std::shared_ptr; - using WeakPtr = std::weak_ptr; - enum class Type : uint32_t { Vertex = 0, @@ -57,24 +52,6 @@ struct Shader using Types = std::set; - struct ResourceBinding - { - using Ptr = std::shared_ptr; - static Ptr CreateCopy(const ResourceBinding& other_resource_binging); - - // ResourceBinding interface - virtual Shader::Type GetShaderType() const = 0; - virtual const std::string& GetArgumentName() const = 0; - virtual bool IsConstant() const = 0; - virtual bool IsAddressable() const = 0; - virtual uint32_t GetResourceCount() const = 0; - virtual const Resource::Locations& GetResourceLocations() const = 0; - virtual void SetResourceLocations(const Resource::Locations& resource_locations) = 0; - - virtual ~ResourceBinding() = default; - }; - - using ResourceBindings = std::vector; using MacroDefinitions = std::map; struct EntryFunction @@ -88,19 +65,17 @@ struct Shader Data::Provider& data_provider; EntryFunction entry_function; MacroDefinitions compile_definitions; - - // Optional parameters: - // by default shaders are precompiled to application resources and loaded through Data::Provider + // Optional parameters (by default shaders are precompiled to application resources and loaded through Data::Provider) std::string source_file_path; std::string source_compile_target; }; // Create Shader instance - static Ptr Create(Type type, Context& context, const Settings& settings); - static Ptr CreateVertex(Context& context, const Settings& settings) { return Create(Type::Vertex, context, settings); } - static Ptr CreatePixel(Context& context, const Settings& settings) { return Create(Type::Pixel, context, settings); } + static Ptr Create(Type type, Context& context, const Settings& settings); + static Ptr CreateVertex(Context& context, const Settings& settings) { return Create(Type::Vertex, context, settings); } + static Ptr CreatePixel(Context& context, const Settings& settings) { return Create(Type::Pixel, context, settings); } - // Auxillary functions + // Auxiliary functions static std::string GetTypeName(Type shader_type) noexcept; // Shader interface @@ -110,6 +85,4 @@ struct Shader virtual ~Shader() = default; }; -using Shaders = std::vector; - } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/Texture.h b/Modules/Graphics/Core/Include/Methane/Graphics/Texture.h index 5c9d8c730..f4ef80a44 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/Texture.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/Texture.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,16 +25,14 @@ Methane graphics interface: graphics texture. #include "Resource.h" -#include +#include +#include namespace Methane::Graphics { struct Texture : virtual Resource { - using Ptr = std::shared_ptr; - using WeakPtr = std::weak_ptr; - enum class Type : uint32_t { Texture = 0, @@ -72,16 +70,16 @@ struct Texture : virtual Resource }; // Create Texture instance - static Ptr CreateRenderTarget(Context& context, const Settings& settings, - const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); - static Ptr CreateFrameBuffer(Context& context, uint32_t frame_buffer_index, - const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); - static Ptr CreateDepthStencilBuffer(Context& context, - const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); - static Ptr CreateImage(Context& context, const Dimensions& dimensions, uint32_t array_length, PixelFormat pixel_format, bool mipmapped, - const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); - static Ptr CreateCube(Context& context, uint32_t dimension_size, uint32_t array_length, PixelFormat pixel_format, bool mipmapped, - const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); + static Ptr CreateRenderTarget(RenderContext& context, const Settings& settings, + const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); + static Ptr CreateFrameBuffer(RenderContext& context, uint32_t frame_buffer_index, + const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); + static Ptr CreateDepthStencilBuffer(RenderContext& context, + const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); + static Ptr CreateImage(Context& context, const Dimensions& dimensions, uint32_t array_length, PixelFormat pixel_format, bool mipmapped, + const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); + static Ptr CreateCube(Context& context, uint32_t dimension_size, uint32_t array_length, PixelFormat pixel_format, bool mipmapped, + const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); // Texture interface virtual const Settings& GetSettings() const = 0; diff --git a/Modules/Graphics/Core/Include/Methane/Graphics/Types.h b/Modules/Graphics/Core/Include/Methane/Graphics/Types.h index 39bc8312e..965802b71 100644 --- a/Modules/Graphics/Core/Include/Methane/Graphics/Types.h +++ b/Modules/Graphics/Core/Include/Methane/Graphics/Types.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -58,16 +58,16 @@ class Point3T : public cml::vector> Point3T(T x, T y, T z) : cml::vector>(x, y, z) { } Point3T(const cml::vector>& v) : cml::vector>(v) { } - T x() const noexcept { return (*this)[0]; } - T y() const noexcept { return (*this)[1]; } - T z() const noexcept { return (*this)[2]; } + T GetX() const noexcept { return (*this)[0]; } + T GetY() const noexcept { return (*this)[1]; } + T GetZ() const noexcept { return (*this)[2]; } - void setX(T x) noexcept { (*this)[0] = x; } - void setY(T y) noexcept { (*this)[1] = y; } - void setZ(T z) noexcept { (*this)[2] = z; } + void SetX(T x) noexcept { (*this)[0] = x; } + void SetY(T y) noexcept { (*this)[1] = y; } + void SetZ(T z) noexcept { (*this)[2] = z; } operator std::string() const - { return "Pt(" + std::to_string(x()) + ", " + std::to_string(y()) + ", " + std::to_string(z()) + ")"; } + { return "Pt(" + std::to_string(GetX()) + ", " + std::to_string(GetY()) + ", " + std::to_string(GetZ()) + ")"; } }; using Point3i = Point3T; @@ -135,19 +135,19 @@ class Color3f : public Vector3f Color3f() = default; Color3f(float r, float g, float b) : Vector3f(r, g, b) { } - float r() const noexcept { return (*this)[0]; } - float g() const noexcept { return (*this)[1]; } - float b() const noexcept { return (*this)[2]; } + float GetR() const noexcept { return (*this)[0]; } + float GetG() const noexcept { return (*this)[1]; } + float GetB() const noexcept { return (*this)[2]; } - void setR(float r) noexcept { (*this)[0] = r; } - void setG(float g) noexcept { (*this)[1] = g; } - void setB(float b) noexcept { (*this)[2] = b; } + void SetR(float r) noexcept { (*this)[0] = r; } + void SetG(float g) noexcept { (*this)[1] = g; } + void SetB(float b) noexcept { (*this)[2] = b; } std::string ToString() const { - return "C(R:" + std::to_string(r()) + - ", G:" + std::to_string(g()) + - ", B:" + std::to_string(b()) + ")"; + return "C(R:" + std::to_string(GetR()) + + ", G:" + std::to_string(GetG()) + + ", B:" + std::to_string(GetB()) + ")"; } }; @@ -160,22 +160,22 @@ class Color4f : public Vector4f Color4f() : Vector4f(0.f, 0.f, 0.f, 0.f) { } Color4f(float r, float g, float b, float a) : Vector4f(r, g, b, a) { } - float r() const noexcept { return (*this)[0]; } - float g() const noexcept { return (*this)[1]; } - float b() const noexcept { return (*this)[2]; } - float a() const noexcept { return (*this)[3]; } + float GetR() const noexcept { return (*this)[0]; } + float GetG() const noexcept { return (*this)[1]; } + float GetB() const noexcept { return (*this)[2]; } + float GetA() const noexcept { return (*this)[3]; } - void setR(float r) noexcept { (*this)[0] = r; } - void setG(float g) noexcept { (*this)[1] = g; } - void setB(float b) noexcept { (*this)[2] = b; } - void setA(float a) noexcept { (*this)[3] = a; } + void SetR(float r) noexcept { (*this)[0] = r; } + void SetG(float g) noexcept { (*this)[1] = g; } + void SetB(float b) noexcept { (*this)[2] = b; } + void SetA(float a) noexcept { (*this)[3] = a; } std::string ToString() const { - return "C(R:" + std::to_string(r()) + - ", G:" + std::to_string(g()) + - ", B:" + std::to_string(b()) + - ", A:" + std::to_string(a()) + ")"; + return "C(R:" + std::to_string(GetR()) + + ", G:" + std::to_string(GetG()) + + ", B:" + std::to_string(GetB()) + + ", A:" + std::to_string(GetA()) + ")"; } }; @@ -197,6 +197,8 @@ enum class PixelFormat Depth32Float }; +using PixelFormats = std::vector; + uint32_t GetPixelSize(PixelFormat data_format) noexcept; template diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/BufferBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/BufferBase.cpp index 813d40b1d..c1dd15354 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/BufferBase.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/BufferBase.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ Base implementation of the buffer interface. #include "DescriptorHeap.h" #include "ContextBase.h" -#include +#include #include diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/BufferBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/BufferBase.h index 2e39b5b7f..b80927d05 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/BufferBase.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/BufferBase.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -35,9 +35,6 @@ class BufferBase , public ResourceNT { public: - using Ptr = std::shared_ptr; - using Ptrs = std::vector; - BufferBase(ContextBase& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); // Resource interface @@ -47,10 +44,10 @@ class BufferBase // Buffer interface Buffer::Type GetBufferType() const noexcept override { return m_settings.type; } - Ptr GetPtr() { return std::dynamic_pointer_cast(shared_from_this()); } + Ptr GetPtr() { return std::dynamic_pointer_cast(shared_from_this()); } std::string GetBufferTypeName() const noexcept { return Buffer::GetBufferTypeName(m_settings.type); } -protected: +private: Settings m_settings; }; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/CommandListBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/CommandListBase.cpp index 1f3608d3c..35ba40f3f 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/CommandListBase.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/CommandListBase.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,11 +21,12 @@ Base implementation of the command list interface. ******************************************************************************/ -#include "CommandListBase.h" -#include "ContextBase.h" +#include "DeviceBase.h" +#include "CommandQueueBase.h" +#include "ProgramBindingsBase.h" #include "ResourceBase.h" -#include +#include #ifdef COMMAND_EXECUTION_LOGGING #include @@ -49,16 +50,52 @@ std::string CommandListBase::GetStateName(State state) } CommandListBase::CommandListBase(CommandQueueBase& command_queue, Type type) - : m_sp_command_queue(command_queue.GetPtr()) - , m_type(type) + : m_type(type) + , m_sp_command_queue(command_queue.GetPtr()) + , m_sp_command_state(CommandState::Create(type)) { ITT_FUNCTION_TASK(); } -void CommandListBase::Commit(bool /*present_drawable*/) +void CommandListBase::Reset(const std::string& debug_group) +{ + ITT_FUNCTION_TASK(); + if (m_state != State::Pending) + throw std::logic_error("Can not reset command list in committed or executing state."); + + // ResetCommandState() must be called from the top-most overridden Reset method + + const bool debug_group_changed = m_open_debug_group != debug_group; + + if (!m_open_debug_group.empty() && debug_group_changed) + { + PopDebugGroup(); + } + + if (!debug_group.empty() && debug_group_changed) + { + PushDebugGroup(debug_group); + } + + m_open_debug_group = debug_group; +} + +void CommandListBase::SetProgramBindings(ProgramBindings& program_bindings, ProgramBindings::ApplyBehavior::Mask apply_behavior) +{ + ITT_FUNCTION_TASK(); + if (m_state != State::Pending) + throw std::logic_error("Can not set program bindings on committed or executing command list."); + + ProgramBindingsBase& program_bindings_base = static_cast(program_bindings); + program_bindings_base.Apply(*this, apply_behavior); + + assert(!!m_sp_command_state); + m_sp_command_state->p_program_bindings = &program_bindings_base; +} + +void CommandListBase::Commit() { ITT_FUNCTION_TASK(); - std::lock_guard guard(m_state_mutex); if (m_state != State::Pending) { @@ -72,24 +109,16 @@ void CommandListBase::Commit(bool /*present_drawable*/) m_committed_frame_index = GetCurrentFrameIndex(); m_state = State::Committed; - if (m_debug_group_opened) + if (!m_open_debug_group.empty()) { PopDebugGroup(); - m_debug_group_opened = false; - } - - // Keep command list from destruction until it's execution is completed - // if weak_from_this is expired, the command list was created explicitly, without make_shared - if (!weak_from_this().expired()) - { - m_sp_self = shared_from_this(); + m_open_debug_group = ""; } } void CommandListBase::Execute(uint32_t frame_index) { ITT_FUNCTION_TASK(); - std::lock_guard guard(m_state_mutex); if (m_state != State::Committed) { @@ -111,50 +140,38 @@ void CommandListBase::Execute(uint32_t frame_index) void CommandListBase::Complete(uint32_t frame_index) { ITT_FUNCTION_TASK(); + if (m_state != State::Executing) { - std::lock_guard guard(m_state_mutex); - - if (m_state != State::Executing) - { - throw std::logic_error("Command list \"" + GetName() + "\" in " + GetStateName(m_state) + " state can not be completed. Only Executing command lists can be completed."); - } + throw std::logic_error("Command list \"" + GetName() + "\" in " + GetStateName(m_state) + " state can not be completed. Only Executing command lists can be completed."); + } - if (m_committed_frame_index != frame_index) - { - throw std::logic_error("Command list \"" + GetName() + "\" committed on frame " + std::to_string(m_committed_frame_index) + " can not be completed on frame " + std::to_string(frame_index)); - } + if (m_committed_frame_index != frame_index) + { + throw std::logic_error("Command list \"" + GetName() + "\" committed on frame " + std::to_string(m_committed_frame_index) + " can not be completed on frame " + std::to_string(frame_index)); + } #ifdef COMMAND_EXECUTION_LOGGING - Platform::PrintToDebugOutput("CommandList \"" + GetName() + "\" was completed on frame " + std::to_string(frame_index)); + Platform::PrintToDebugOutput("CommandList \"" + GetName() + "\" was completed on frame " + std::to_string(frame_index)); #endif - m_state = State::Pending; - } - - GetCommandQueueBase().OnCommandListCompleted(*this, frame_index); - - // Release command list shared pointer, so it can be deleted externally - m_sp_self.reset(); + m_state = State::Pending; } bool CommandListBase::IsExecutingOnAnyFrame() const { ITT_FUNCTION_TASK(); - std::lock_guard guard(m_state_mutex); return m_state == State::Executing; } bool CommandListBase::IsCommitted(uint32_t frame_index) const { ITT_FUNCTION_TASK(); - std::lock_guard guard(m_state_mutex); return m_state == State::Committed && m_committed_frame_index == frame_index; } bool CommandListBase::IsExecuting(uint32_t frame_index) const { ITT_FUNCTION_TASK(); - std::lock_guard guard(m_state_mutex); return m_state == State::Executing && m_committed_frame_index == frame_index; } @@ -168,27 +185,15 @@ CommandQueue& CommandListBase::GetCommandQueue() uint32_t CommandListBase::GetCurrentFrameIndex() const { ITT_FUNCTION_TASK(); - return GetCommandQueueBase().GetContext().GetFrameBufferIndex(); -} - -void CommandListBase::ResetCommandState() -{ - m_command_state.sp_resource_bindings.reset(); -} - -void CommandListBase::SetResourceBindings(Program::ResourceBindings& resource_bindings, Program::ResourceBindings::ApplyBehavior::Mask apply_behavior) -{ - ITT_FUNCTION_TASK(); - resource_bindings.Apply(*this, apply_behavior); - m_command_state.sp_resource_bindings = static_cast(resource_bindings).GetPtr(); + return GetCommandQueueBase().GetCurrentFrameBufferIndex(); } -void CommandListBase::SetResourceTransitionBarriers(const Resource::Refs& resources, ResourceBase::State state_before, ResourceBase::State state_after) +void CommandListBase::SetResourceTransitionBarriers(const Refs& resources, ResourceBase::State state_before, ResourceBase::State state_after) { ITT_FUNCTION_TASK(); ResourceBase::Barriers resource_barriers; resource_barriers.reserve(resources.size()); - for (const Resource::Ref& resource_ref : resources) + for (const Ref& resource_ref : resources) { resource_barriers.push_back({ ResourceBase::Barrier::Type::Transition, @@ -200,6 +205,26 @@ void CommandListBase::SetResourceTransitionBarriers(const Resource::Refs& resour SetResourceBarriers(resource_barriers); } +void CommandListBase::ResetCommandState() +{ + ITT_FUNCTION_TASK(); + m_sp_command_state = CommandState::Create(m_type); +} + +CommandListBase::CommandState& CommandListBase::GetCommandState() +{ + ITT_FUNCTION_TASK(); + assert(!!m_sp_command_state); + return *m_sp_command_state; +} + +const CommandListBase::CommandState& CommandListBase::GetCommandState() const +{ + ITT_FUNCTION_TASK(); + assert(!!m_sp_command_state); + return *m_sp_command_state; +} + CommandQueueBase& CommandListBase::GetCommandQueueBase() { ITT_FUNCTION_TASK(); @@ -213,4 +238,4 @@ const CommandQueueBase& CommandListBase::GetCommandQueueBase() const return static_cast(*m_sp_command_queue); } -} // namespace Methane::Graphics \ No newline at end of file +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/CommandListBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/CommandListBase.h index 56d871c18..549eb235f 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/CommandListBase.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/CommandListBase.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -37,6 +37,7 @@ namespace Methane::Graphics { class CommandQueueBase; +class ProgramBindingsBase; class CommandListBase : public ObjectBase @@ -46,9 +47,6 @@ class CommandListBase friend class CommandQueueBase; public: - using Ptr = std::shared_ptr; - using WeakPtr = std::weak_ptr; - enum State { Pending, @@ -58,15 +56,26 @@ class CommandListBase struct CommandState { - Program::ResourceBindings::Ptr sp_resource_bindings; + // NOTE: + // Command state uses raw pointers instead of smart pointers for performance reasons: + // - shared pointers can not be used here, because they keep resources from deletion on context release + // - weak pointer should not be used too because 'lock' operation has significant performance overhead + // - even if raw pointer becomes obsolete it won't be a problem because it is used only for address comparison with another raw pointer + ProgramBindingsBase* p_program_bindings = nullptr; + + static UniquePtr Create(Type command_list_type); + + protected: + CommandState() = default; }; CommandListBase(CommandQueueBase& command_queue, Type type); // CommandList interface - Type GetType() const override { return m_type; } - void SetResourceBindings(Program::ResourceBindings& resource_bindings, Program::ResourceBindings::ApplyBehavior::Mask apply_behavior) override; - void Commit(bool present_drawable) override; + Type GetType() const override { return m_type; } + void Reset(const std::string& debug_group = "") override; + void SetProgramBindings(ProgramBindings& program_bindings, ProgramBindings::ApplyBehavior::Mask apply_behavior) override; + void Commit() override; CommandQueue& GetCommandQueue() override; // CommandListBase interface @@ -74,12 +83,16 @@ class CommandListBase virtual void Execute(uint32_t frame_index); virtual void Complete(uint32_t frame_index); - void SetResourceTransitionBarriers(const Resource::Refs& resources, ResourceBase::State state_before, ResourceBase::State state_after); - const CommandState& GetCommandState() const { return m_command_state; } - Ptr GetPtr() { return shared_from_this(); } - void SetDebugGroupOpened(bool debug_group_opened) { m_debug_group_opened = debug_group_opened; } + void SetResourceTransitionBarriers(const Refs& resources, ResourceBase::State state_before, ResourceBase::State state_after); + void SetOpenDebugGroup(const std::string& debug_group) { m_open_debug_group = debug_group; } + const ProgramBindingsBase* GetProgramBindings() const { return GetCommandState().p_program_bindings; } + Ptr GetPtr() { return shared_from_this(); } protected: + void ResetCommandState(); + CommandState& GetCommandState(); + const CommandState& GetCommandState() const; + CommandQueueBase& GetCommandQueueBase(); const CommandQueueBase& GetCommandQueueBase() const; @@ -89,22 +102,18 @@ class CommandListBase bool IsExecuting(uint32_t frame_index) const; bool IsExecuting() const { return IsExecuting(GetCurrentFrameIndex()); } uint32_t GetCurrentFrameIndex() const; - void ResetCommandState(); - - CommandQueue::Ptr m_sp_command_queue; - bool m_debug_group_opened = false; private: static std::string GetStateName(State state); - + using ExecutingOnFrame = std::map; - const Type m_type; - Ptr m_sp_self; - uint32_t m_committed_frame_index = 0; - State m_state = State::Pending; - mutable std::mutex m_state_mutex; - CommandState m_command_state; + const Type m_type; + Ptr m_sp_command_queue; + UniquePtr m_sp_command_state; + std::string m_open_debug_group; + uint32_t m_committed_frame_index = 0; + State m_state = State::Pending; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/CommandListState.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/CommandListState.cpp new file mode 100644 index 000000000..f89ee5a32 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/CommandListState.cpp @@ -0,0 +1,39 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/CommandListState.cpp +Command list state factory implementation + +******************************************************************************/ + +#include "CommandListBase.h" +#include "RenderCommandListBase.h" + +namespace Methane::Graphics +{ + +UniquePtr CommandListBase::CommandState::Create(Type command_list_type) +{ + switch(command_list_type) + { + case Type::Render: return std::make_unique(); + default: return UniquePtr(new CommandState()); + } +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/CommandQueueBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/CommandQueueBase.cpp index 0917b9c33..ae7396a49 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/CommandQueueBase.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/CommandQueueBase.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,9 +22,9 @@ Base implementation of the command queue interface. ******************************************************************************/ #include "CommandQueueBase.h" -#include "ContextBase.h" +#include "RenderContextBase.h" -#include +#include #ifdef COMMAND_EXECUTION_LOGGING #include @@ -35,9 +35,8 @@ Base implementation of the command queue interface. namespace Methane::Graphics { -CommandQueueBase::CommandQueueBase(ContextBase& context, bool execution_state_tracking) +CommandQueueBase::CommandQueueBase(ContextBase& context) : m_context(context) - , m_execution_state_tracking(execution_state_tracking) { ITT_FUNCTION_TASK(); } @@ -45,117 +44,35 @@ CommandQueueBase::CommandQueueBase(ContextBase& context, bool execution_state_tr CommandQueueBase::~CommandQueueBase() { ITT_FUNCTION_TASK(); - std::lock_guard guard(m_executing_mutex); - assert(m_executing_on_frames.empty()); } -void CommandQueueBase::Execute(const CommandList::Refs& command_lists) +void CommandQueueBase::Execute(const Refs& command_lists) { ITT_FUNCTION_TASK(); - if (m_execution_state_tracking) - { - m_executing_mutex.lock(); - } - - const uint32_t frame_index = m_context.GetFrameBufferIndex(); - if (m_execution_state_tracking) - { - if (m_executing_on_frames.find(frame_index) != m_executing_on_frames.end()) - { - m_executing_mutex.unlock(); - return; - } + const uint32_t frame_index = GetCurrentFrameBufferIndex(); #ifdef COMMAND_EXECUTION_LOGGING Platform::PrintToDebugOutput("CommandQueue \"" + GetName() + "\" is executing on frame " + std::to_string(frame_index)); #endif - m_executing_on_frames.insert(frame_index); - } - for (const auto& command_list_ref : command_lists) { if (std::addressof(command_list_ref.get().GetCommandQueue()) != std::addressof(*this)) { - throw new std::runtime_error("Can not execute command list created in different command queue."); + throw std::runtime_error("Can not execute command list created in different command queue."); } CommandListBase& command_list = dynamic_cast(command_list_ref.get()); command_list.Execute(frame_index); - - if (m_execution_state_tracking) - { - m_executing_command_lists.push_back(command_list.GetPtr()); - } } - - if (m_execution_state_tracking) - { - m_executing_mutex.unlock(); - } -} - -bool CommandQueueBase::IsExecuting(uint32_t frame_index) const -{ - ITT_FUNCTION_TASK(); - if (!m_execution_state_tracking) - return false; - - std::lock_guard guard(m_executing_mutex); - return m_executing_on_frames.find(frame_index) != m_executing_on_frames.end(); } -bool CommandQueueBase::IsExecuting() const +uint32_t CommandQueueBase::GetCurrentFrameBufferIndex() const { - ITT_FUNCTION_TASK(); - return IsExecuting(m_context.GetFrameBufferIndex()); -} - -void CommandQueueBase::OnCommandListCompleted(CommandListBase& /*command_list*/, uint32_t frame_index) -{ - ITT_FUNCTION_TASK(); - if (!m_execution_state_tracking) - return; - - std::lock_guard guard(m_executing_mutex); - - bool all_command_lists_completed = true; - for (auto executing_command_list_it = m_executing_command_lists.begin(); - executing_command_list_it != m_executing_command_lists.end();) - { - CommandListBase::WeakPtr& wp_cmd_list = *executing_command_list_it; - CommandListBase::Ptr sp_cmd_list = wp_cmd_list.lock(); - if (!sp_cmd_list) - { - executing_command_list_it = m_executing_command_lists.erase(executing_command_list_it); - continue; - } - - CommandListBase& cmd_list = static_cast(*sp_cmd_list); - if (cmd_list.IsExecuting(frame_index)) - { - all_command_lists_completed = false; - break; - } - else if (!cmd_list.IsExecutingOnAnyFrame()) - { - executing_command_list_it = m_executing_command_lists.erase(executing_command_list_it); - } - else - { - executing_command_list_it++; - } - } - - if (all_command_lists_completed) - { -#ifdef COMMAND_EXECUTION_LOGGING - Platform::PrintToDebugOutput("CommandQueue \"" + GetName() + "\" execution completed on frame " + std::to_string(frame_index) + "\n\n"); -#endif - m_executing_on_frames.erase(frame_index); - m_context.OnCommandQueueCompleted(*this, frame_index); - } + return m_context.GetType() == Context::Type::Render + ? dynamic_cast(m_context).GetFrameBufferIndex() + : 0u; } -} // namespace Methane::Graphics \ No newline at end of file +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/CommandQueueBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/CommandQueueBase.h index afd2f6968..8a428fbc6 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/CommandQueueBase.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/CommandQueueBase.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -37,7 +37,7 @@ Base implementation of the command queue interface. namespace Methane::Graphics { -class ContextBase; +class RenderContextBase; class CommandQueueBase : public ObjectBase @@ -47,28 +47,21 @@ class CommandQueueBase friend class CommandListBase; public: - CommandQueueBase(ContextBase& context, bool execution_state_tracking); + CommandQueueBase(ContextBase& context); ~CommandQueueBase() override; // CommandQueue interface - void Execute(const CommandList::Refs& command_lists) override; + void Execute(const Refs& command_lists) override; - Ptr GetPtr() { return shared_from_this(); } - ContextBase& GetContext() { return m_context; } - const ContextBase& GetContext() const { return m_context; } - bool IsExecuting(uint32_t frame_index) const; - bool IsExecuting() const; + Ptr GetPtr() { return shared_from_this(); } + ContextBase& GetContext() { return m_context; } + const ContextBase& GetContext() const { return m_context; } protected: - void OnCommandListCompleted(CommandListBase& command_list, uint32_t frame_index); - - using CommandLists = std::list; + uint32_t GetCurrentFrameBufferIndex() const; +private: ContextBase& m_context; - const bool m_execution_state_tracking; - std::set m_executing_on_frames; - CommandLists m_executing_command_lists; - mutable std::mutex m_executing_mutex; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/ContextBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/ContextBase.cpp index a2bd8aa90..4e2428d5b 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/ContextBase.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/ContextBase.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,8 +23,10 @@ Base implementation of the context interface. #include "ContextBase.h" #include "DeviceBase.h" +#include "CommandQueueBase.h" -#include +#include +#include #ifdef COMMAND_EXECUTION_LOGGING #include @@ -35,7 +37,8 @@ Base implementation of the context interface. namespace Methane::Graphics { -std::string GetWaitForName(Context::WaitFor wait_for) +#ifdef COMMAND_EXECUTION_LOGGING +static std::string GetWaitForName(Context::WaitFor wait_for) { ITT_FUNCTION_TASK(); switch (wait_for) @@ -46,12 +49,12 @@ std::string GetWaitForName(Context::WaitFor wait_for) } return ""; } +#endif -ContextBase::ContextBase(DeviceBase& device, const Settings& settings) - : m_sp_device(device.GetPtr()) - , m_settings(settings) +ContextBase::ContextBase(DeviceBase& device, Type type) + : m_type(type) + , m_sp_device(device.GetPtr()) , m_resource_manager(*this) - , m_frame_buffer_index(0) { ITT_FUNCTION_TASK(); } @@ -76,18 +79,14 @@ void ContextBase::WaitForGpu(WaitFor wait_for) Platform::PrintToDebugOutput(GetWaitForName(wait_for) + " in context \"" + GetName() + "\""); #endif - m_fps_counter.OnGpuFramePresentWait(); -} - -void ContextBase::Resize(const FrameSize& frame_size) -{ - ITT_FUNCTION_TASK(); - -#ifdef COMMAND_EXECUTION_LOGGING - Platform::PrintToDebugOutput("RESIZE context \"" + GetName() + "\" from " + static_cast(m_settings.frame_size) + " to " + static_cast(frame_size)); -#endif - - m_settings.frame_size = frame_size; + if (wait_for == WaitFor::ResourcesUploaded) + { + SCOPE_TIMER("ContextBase::WaitForGpu::ResourcesUploaded"); + assert(!!m_sp_upload_fence); + OnGpuWaitStart(wait_for); + m_sp_upload_fence->Flush(); + OnGpuWaitComplete(wait_for); + } } void ContextBase::Reset(Device& device) @@ -100,18 +99,22 @@ void ContextBase::Reset(Device& device) WaitForGpu(WaitFor::RenderComplete); Release(); - Initialize(device, false); + Initialize(static_cast(device), false); } -void ContextBase::Present() +void ContextBase::Reset() { ITT_FUNCTION_TASK(); #ifdef COMMAND_EXECUTION_LOGGING - Platform::PrintToDebugOutput("PRESENT frame " + std::to_string(m_frame_buffer_index) + " in context \"" + GetName() + "\""); + Platform::PrintToDebugOutput("RESET context \"" + GetName() + "\".."); #endif - m_fps_counter.OnCpuFrameReadyToPresent(); + WaitForGpu(WaitFor::RenderComplete); + + Ptr sp_device = m_sp_device; + Release(); + Initialize(*sp_device, true); } void ContextBase::AddCallback(Callback& callback) @@ -124,76 +127,49 @@ void ContextBase::RemoveCallback(Callback& callback) { ITT_FUNCTION_TASK(); const auto callback_it = std::find_if(m_callbacks.begin(), m_callbacks.end(), - [&callback](const Callback::Ref& callback_ref) - { return std::addressof(callback_ref.get()) == std::addressof(callback); }); + [&callback](const Ref& callback_ref) + { + return std::addressof(callback_ref.get()) == std::addressof(callback); + }); assert(callback_it != m_callbacks.end()); if (callback_it == m_callbacks.end()) return; - + m_callbacks.erase(callback_it); } - + void ContextBase::OnGpuWaitComplete(WaitFor wait_for) { ITT_FUNCTION_TASK(); - if (wait_for == WaitFor::FramePresented) - { - m_fps_counter.OnGpuFramePresented(); - } m_resource_manager.GetReleasePool().ReleaseResources(); } -void ContextBase::OnCpuPresentComplete() -{ - ITT_FUNCTION_TASK(); - -#ifdef COMMAND_EXECUTION_LOGGING - Platform::PrintToDebugOutput("PRESENT COMPLETE for context \"" + GetName() + "\""); -#endif - - m_fps_counter.OnCpuFramePresented(); -} - -void ContextBase::ResetWithSettings(const Settings& settings) -{ - ITT_FUNCTION_TASK(); - -#ifdef COMMAND_EXECUTION_LOGGING - Platform::PrintToDebugOutput("RESET context \"" + GetName() + "\" with new settings."); -#endif - - WaitForGpu(WaitFor::RenderComplete); - - DeviceBase::Ptr sp_device = m_sp_device; - m_settings = settings; - - Release(); - Initialize(*sp_device, true); -} - void ContextBase::Release() { ITT_FUNCTION_TASK(); + m_sp_device.reset(); + #ifdef COMMAND_EXECUTION_LOGGING Platform::PrintToDebugOutput("RELEASE context \"" + GetName() + "\""); #endif - m_sp_render_cmd_queue.reset(); m_sp_upload_cmd_queue.reset(); m_sp_upload_cmd_list.reset(); + m_sp_upload_fence.reset(); - for (const Callback::Ref& callback_ref : m_callbacks) + for (const Ref& callback_ref : m_callbacks) { callback_ref.get().OnContextReleased(); } m_resource_manager_init_settings.default_heap_sizes = m_resource_manager.GetDescriptorHeapSizes(true, false); m_resource_manager_init_settings.shader_visible_heap_sizes = m_resource_manager.GetDescriptorHeapSizes(true, true); + m_resource_manager.Release(); } -void ContextBase::Initialize(Device& device, bool deferred_heap_allocation) +void ContextBase::Initialize(DeviceBase& device, bool deferred_heap_allocation) { ITT_FUNCTION_TASK(); @@ -201,8 +177,9 @@ void ContextBase::Initialize(Device& device, bool deferred_heap_allocation) Platform::PrintToDebugOutput("INITIALIZE context \"" + GetName() + "\""); #endif - m_sp_device = static_cast(device).GetPtr(); - + m_sp_device = device.GetPtr(); + m_sp_upload_fence = Fence::Create(GetUploadCommandQueue()); + const std::string& context_name = GetName(); if (!context_name.empty()) { @@ -215,25 +192,15 @@ void ContextBase::Initialize(Device& device, bool deferred_heap_allocation) m_resource_manager_init_settings.default_heap_sizes = {}; m_resource_manager_init_settings.shader_visible_heap_sizes = {}; } + m_resource_manager.Initialize(m_resource_manager_init_settings); - for (const Callback::Ref& callback_ref : m_callbacks) + for (const Ref& callback_ref : m_callbacks) { callback_ref.get().OnContextInitialized(); } } -CommandQueue& ContextBase::GetRenderCommandQueue() -{ - ITT_FUNCTION_TASK(); - if (!m_sp_render_cmd_queue) - { - m_sp_render_cmd_queue = CommandQueue::Create(*this); - m_sp_render_cmd_queue->SetName("Render Command Queue"); - } - return *m_sp_render_cmd_queue; -} - CommandQueue& ContextBase::GetUploadCommandQueue() { ITT_FUNCTION_TASK(); @@ -245,13 +212,12 @@ CommandQueue& ContextBase::GetUploadCommandQueue() return *m_sp_upload_cmd_queue; } -RenderCommandList& ContextBase::GetUploadCommandList() +BlitCommandList& ContextBase::GetUploadCommandList() { ITT_FUNCTION_TASK(); if (!m_sp_upload_cmd_list) { - RenderPass::Ptr sp_empty_pass = RenderPass::Create(*this, RenderPass::Settings()); - m_sp_upload_cmd_list = RenderCommandList::Create(GetUploadCommandQueue(), *sp_empty_pass); + m_sp_upload_cmd_list = BlitCommandList::Create(GetUploadCommandQueue()); m_sp_upload_cmd_list->SetName("Upload Command List"); } return *m_sp_upload_cmd_list; @@ -263,6 +229,12 @@ Device& ContextBase::GetDevice() assert(!!m_sp_device); return *m_sp_device; } + +CommandQueueBase& ContextBase::GetUploadCommandQueueBase() +{ + ITT_FUNCTION_TASK(); + return static_cast(GetUploadCommandQueue()); +} DeviceBase& ContextBase::GetDeviceBase() { @@ -277,48 +249,14 @@ const DeviceBase& ContextBase::GetDeviceBase() const return static_cast(*m_sp_device); } -bool ContextBase::SetVSyncEnabled(bool vsync_enabled) -{ - ITT_FUNCTION_TASK(); - if (m_settings.vsync_enabled == vsync_enabled) - return false; - - m_settings.vsync_enabled = vsync_enabled; - return true; -} - -bool ContextBase::SetFrameBuffersCount(uint32_t frame_buffers_count) -{ - ITT_FUNCTION_TASK(); - frame_buffers_count = std::min(std::max(2u, frame_buffers_count), 10u); - - if (m_settings.frame_buffers_count == frame_buffers_count) - return false; - - Settings new_settings = m_settings; - new_settings.frame_buffers_count = frame_buffers_count; - ResetWithSettings(new_settings); - - return true; -} - -bool ContextBase::SetFullScreen(bool is_full_screen) -{ - ITT_FUNCTION_TASK(); - if (m_settings.is_full_screen == is_full_screen) - return false; - - // No need to reset context for switching to full-screen - // Application window state is kept in sync with context by the user code and handles window resizing - m_settings.is_full_screen = is_full_screen; - return true; -} - void ContextBase::SetName(const std::string& name) { ITT_FUNCTION_TASK(); ObjectBase::SetName(name); GetDevice().SetName(name + " Device"); + + if (m_sp_upload_fence) + m_sp_upload_fence->SetName(name + " Upload Fence"); } void ContextBase::UploadResources() @@ -329,9 +267,14 @@ void ContextBase::UploadResources() Platform::PrintToDebugOutput("UPLOAD resources for context \"" + GetName() + "\""); #endif - GetUploadCommandList().Commit(false); + GetUploadCommandList().Commit(); GetUploadCommandQueue().Execute({ GetUploadCommandList() }); WaitForGpu(WaitFor::ResourcesUploaded); } +void ContextBase::SetDevice(DeviceBase& device) +{ + m_sp_device = device.GetPtr(); +} + } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/ContextBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/ContextBase.h index 8b9b5ef33..e5fc7380d 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/ContextBase.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/ContextBase.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,84 +23,72 @@ Base implementation of the context interface. #pragma once -#include -#include -#include - #include "ObjectBase.h" -#include "DeviceBase.h" -#include "CommandQueueBase.h" -#include "RenderCommandListBase.h" -#include "RenderStateBase.h" -#include "RenderPassBase.h" #include "ResourceManager.h" +#include +#include +#include + #include -#include -#include namespace Methane::Graphics { +class DeviceBase; +struct CommandQueue; +class CommandQueueBase; + class ContextBase : public ObjectBase - , public Context + , public virtual Context + , public IContextNT { public: - ContextBase(DeviceBase& device, const Settings& settings); + ContextBase(DeviceBase& device, Type type); // Context interface - void CompleteInitialization() override; - void WaitForGpu(WaitFor wait_for) override; - void Resize(const FrameSize& frame_size) override; - void Reset(Device& device) override; - void Reset() override { ResetWithSettings(m_settings); } - void Present() override; - void AddCallback(Callback& callback) override; - void RemoveCallback(Callback& callback) override; - CommandQueue& GetRenderCommandQueue() override; - CommandQueue& GetUploadCommandQueue() override; - RenderCommandList& GetUploadCommandList() override; - Device& GetDevice() override; - const Settings& GetSettings() const override { return m_settings; } - uint32_t GetFrameBufferIndex() const override { return m_frame_buffer_index; } - const FpsCounter& GetFpsCounter() const override { return m_fps_counter; } - bool SetVSyncEnabled(bool vsync_enabled) override; - bool SetFrameBuffersCount(uint32_t frame_buffers_count) override; - bool SetFullScreen(bool is_full_screen) override; + Type GetType() const override { return m_type; } + void CompleteInitialization() override; + void WaitForGpu(WaitFor wait_for) override; + void Reset(Device& device) override; + void Reset() override; + void AddCallback(Callback& callback) override; + void RemoveCallback(Callback& callback) override; + CommandQueue& GetUploadCommandQueue() override; + BlitCommandList& GetUploadCommandList() override; + Device& GetDevice() override; // ContextBase interface - virtual void OnCommandQueueCompleted(CommandQueue& cmd_queue, uint32_t frame_index) = 0; + virtual void Initialize(DeviceBase& device, bool deferred_heap_allocation); + virtual void Release(); // Object interface void SetName(const std::string& name) override; - ResourceManager& GetResourceManager() { return m_resource_manager; } - - DeviceBase& GetDeviceBase(); - const DeviceBase& GetDeviceBase() const; + ResourceManager& GetResourceManager() { return m_resource_manager; } + const ResourceManager& GetResourceManager() const { return m_resource_manager; } + CommandQueueBase& GetUploadCommandQueueBase(); + DeviceBase& GetDeviceBase(); + const DeviceBase& GetDeviceBase() const; protected: void UploadResources(); - void OnGpuWaitComplete(WaitFor wait_for); - void OnCpuPresentComplete(); - void ResetWithSettings(const Settings& settings); + void SetDevice(DeviceBase& device); - virtual void Release(); - virtual void Initialize(Device& device, bool deferred_heap_allocation); - - using Callbacks = std::vector; - - DeviceBase::Ptr m_sp_device; - Settings m_settings; - ResourceManager::Settings m_resource_manager_init_settings = { true }; - ResourceManager m_resource_manager; - Callbacks m_callbacks; // ORDER: Keep callbacks before resources for correct auto-delete - CommandQueue::Ptr m_sp_render_cmd_queue; - CommandQueue::Ptr m_sp_upload_cmd_queue; - RenderCommandList::Ptr m_sp_upload_cmd_list; - std::atomic m_frame_buffer_index; - FpsCounter m_fps_counter; + // ContextBase interface + virtual void OnGpuWaitStart(WaitFor wait_for) {} + virtual void OnGpuWaitComplete(WaitFor wait_for); + +private: + const Type m_type; + Ptr m_sp_device; + ResourceManager::Settings m_resource_manager_init_settings = { true }; + ResourceManager m_resource_manager; + Refs m_callbacks; // ORDER: Keep callbacks before resources for correct auto-delete + Ptr m_sp_upload_cmd_queue; + Ptr m_sp_upload_cmd_list; + UniquePtr m_sp_upload_fence; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DescriptorHeap.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DescriptorHeap.cpp index e5acf1e21..b684d084c 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DescriptorHeap.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DescriptorHeap.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,14 +24,14 @@ Descriptor Heap is a platform abstraction of DirectX 12 descriptor heaps #include "DescriptorHeap.h" #include "ResourceBase.h" -#include +#include #include namespace Methane::Graphics { -DescriptorHeap::Reservation::Reservation(Ref in_heap, const Range& in_constant_range, const Range& in_mutable_range) +DescriptorHeap::Reservation::Reservation(const Ref& in_heap, const Range& in_constant_range, const Range& in_mutable_range) : heap(in_heap) , constant_range(in_constant_range) , mutable_range(in_mutable_range) @@ -64,7 +64,7 @@ DescriptorHeap::~DescriptorHeap() m_free_ranges == RangeSet({ { 0, m_deferred_size } })); } -int32_t DescriptorHeap::AddResource(const ResourceBase& resource) +Data::Index DescriptorHeap::AddResource(const ResourceBase& resource) { ITT_FUNCTION_TASK(); @@ -86,13 +86,13 @@ int32_t DescriptorHeap::AddResource(const ResourceBase& resource) m_resources.push_back(&resource); - const Index resource_index = static_cast(m_resources.size() - 1); + const Data::Index resource_index = static_cast(m_resources.size() - 1); m_free_ranges.Remove(Range(resource_index, resource_index + 1)); return static_cast(resource_index); } -int32_t DescriptorHeap::ReplaceResource(const ResourceBase& resource, uint32_t at_index) +Data::Index DescriptorHeap::ReplaceResource(const ResourceBase& resource, Data::Index at_index) { ITT_FUNCTION_TASK(); @@ -108,7 +108,7 @@ int32_t DescriptorHeap::ReplaceResource(const ResourceBase& resource, uint32_t a return at_index; } -void DescriptorHeap::RemoveResource(uint32_t at_index) +void DescriptorHeap::RemoveResource(Data::Index at_index) { ITT_FUNCTION_TASK(); @@ -124,7 +124,7 @@ void DescriptorHeap::RemoveResource(uint32_t at_index) m_free_ranges.Add(Range(at_index, at_index + 1)); } -DescriptorHeap::RangePtr DescriptorHeap::ReserveRange(Index length) +Ptr DescriptorHeap::ReserveRange(Data::Size length) { ITT_FUNCTION_TASK(); @@ -141,7 +141,7 @@ DescriptorHeap::RangePtr DescriptorHeap::ReserveRange(Index length) { if (m_settings.deferred_allocation) { - RangePtr sp_reserved_range(new Range(m_deferred_size, m_deferred_size + length)); + Ptr sp_reserved_range(new Range(m_deferred_size, m_deferred_size + length)); m_deferred_size += length; return sp_reserved_range; } @@ -149,7 +149,7 @@ DescriptorHeap::RangePtr DescriptorHeap::ReserveRange(Index length) return nullptr; } - RangePtr sp_reserved_range(new Range(free_range_it->GetStart(), free_range_it->GetStart() + length)); + Ptr sp_reserved_range(new Range(free_range_it->GetStart(), free_range_it->GetStart() + length)); m_free_ranges.Remove(*sp_reserved_range); return sp_reserved_range; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DescriptorHeap.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DescriptorHeap.h index d038e5c02..c4cdace9c 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DescriptorHeap.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DescriptorHeap.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,9 +24,9 @@ Descriptor Heap is a platform abstraction of DirectX 12 descriptor heaps #pragma once #include +#include +#include -#include -#include #include #include @@ -55,68 +55,61 @@ class DescriptorHeap struct Settings { - Type type; - uint32_t size; - bool deferred_allocation; - bool shader_visible; + Type type; + Data::Size size; + bool deferred_allocation; + bool shader_visible; }; - using Ref = std::reference_wrapper; using Types = std::set; - using Index = uint32_t; - using Range = Methane::Data::Range; - using RangePtr = std::unique_ptr; + using Range = Methane::Data::Range; struct Reservation { - Ref heap; + Ref heap; Range constant_range; Range mutable_range; - Reservation(Ref in_heap, const Range& in_constant_range, const Range& in_mutable_range); + Reservation(const Ref& in_heap, const Range& in_constant_range, const Range& in_mutable_range); const Range& GetRange(bool is_constant) const { return is_constant ? constant_range : mutable_range; } }; - using Ptr = std::shared_ptr; - static Ptr Create(ContextBase& context, const Settings& settings); + static Ptr Create(ContextBase& context, const Settings& settings); virtual ~DescriptorHeap(); // DescriptorHeap interface - virtual int32_t AddResource(const ResourceBase& resource); - virtual int32_t ReplaceResource(const ResourceBase& resource, uint32_t at_index); - virtual void RemoveResource(uint32_t at_index); - virtual void Allocate() { m_allocated_size = m_deferred_size; } + virtual Data::Index AddResource(const ResourceBase& resource); + virtual Data::Index ReplaceResource(const ResourceBase& resource, Data::Index at_index); + virtual void RemoveResource(Data::Index at_index); + virtual void Allocate() { m_allocated_size = m_deferred_size; } - RangePtr ReserveRange(Index length); - void ReleaseRange(const Range& range); + Ptr ReserveRange(Data::Size length); + void ReleaseRange(const Range& range); const Settings& GetSettings() const { return m_settings; } - uint32_t GetDeferredSize() const { return m_deferred_size; } - uint32_t GetAllocatedSize() const { return m_allocated_size; } + Data::Size GetDeferredSize() const { return m_deferred_size; } + Data::Size GetAllocatedSize() const { return m_allocated_size; } std::string GetTypeName() const { return GetTypeName(m_settings.type); } const ResourceBase* GetResource(uint32_t descriptor_index) const { return m_resources[descriptor_index]; } - bool IsShaderVisible() const { return m_settings.shader_visible && IsShaderVisibileHeapType(m_settings.type); } + bool IsShaderVisible() const { return m_settings.shader_visible && IsShaderVisibleHeapType(m_settings.type); } - static bool IsShaderVisibileHeapType(Type heap_type) { return heap_type == Type::ShaderResources || heap_type == Type::Samplers; } + static bool IsShaderVisibleHeapType(Type heap_type) { return heap_type == Type::ShaderResources || heap_type == Type::Samplers; } static std::string GetTypeName(Type heap_type); protected: DescriptorHeap(ContextBase& context, const Settings& settings); using ResourcePtrs = std::vector; - using RangeSet = Methane::Data::RangeSet; + using RangeSet = Data::RangeSet; ContextBase& m_context; const Settings m_settings; - uint32_t m_deferred_size; - uint32_t m_allocated_size = 0; + Data::Size m_deferred_size; + Data::Size m_allocated_size = 0; ResourcePtrs m_resources; RangeSet m_free_ranges; std::mutex m_modification_mutex; }; -using DescriptorHeaps = std::vector; -using DescriptorHeapRefs = std::vector; - } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DeviceBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DeviceBase.cpp index 775db6314..8cc6f19c7 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DeviceBase.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DeviceBase.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ Base implementation of the device interface. #include "DeviceBase.h" -#include +#include #include #include @@ -88,16 +88,16 @@ std::string DeviceBase::ToString() const noexcept return ss.str(); } -Device::Ptr SystemBase::GetNextGpuDevice(const Device& device) const +Ptr SystemBase::GetNextGpuDevice(const Device& device) const { ITT_FUNCTION_TASK(); - Device::Ptr sp_next_device; + Ptr sp_next_device; if (m_devices.empty()) return sp_next_device; auto device_it = std::find_if(m_devices.begin(), m_devices.end(), - [&device](const Device::Ptr& sp_system_device) + [&device](const Ptr& sp_system_device) { return std::addressof(device) == sp_system_device.get(); }); if (device_it == m_devices.end()) return sp_next_device; @@ -105,14 +105,14 @@ Device::Ptr SystemBase::GetNextGpuDevice(const Device& device) const return device_it == m_devices.end() - 1 ? m_devices.front() : *(device_it + 1); } -Device::Ptr SystemBase::GetSoftwareGpuDevice() const +Ptr SystemBase::GetSoftwareGpuDevice() const { ITT_FUNCTION_TASK(); auto sw_device_it = std::find_if(m_devices.begin(), m_devices.end(), - [](const Device::Ptr& sp_system_device) + [](const Ptr& sp_system_device) { return sp_system_device && sp_system_device->IsSoftwareAdapter(); }); - return sw_device_it != m_devices.end() ? *sw_device_it : Device::Ptr(); + return sw_device_it != m_devices.end() ? *sw_device_it : Ptr(); } std::string SystemBase::ToString() const noexcept @@ -121,7 +121,7 @@ std::string SystemBase::ToString() const noexcept std::stringstream ss; ss << m_devices.size() << " system graphics device" << (m_devices.size() > 1 ? "s:" : ":") << std::endl; - for(const Device::Ptr& sp_device : m_devices) + for(const Ptr& sp_device : m_devices) { assert(sp_device); if (!sp_device) continue; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DeviceBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DeviceBase.h index d68dfb73f..1adbd8d41 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DeviceBase.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DeviceBase.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -36,8 +36,6 @@ class DeviceBase , public std::enable_shared_from_this { public: - using Ptr = std::shared_ptr; - DeviceBase(const std::string& adapter_name, bool is_software_adapter, Feature::Mask supported_features); // Device interface @@ -48,9 +46,9 @@ class DeviceBase void Notify(Notification notification) override; std::string ToString() const noexcept override; - Ptr GetPtr() { return shared_from_this(); } + Ptr GetPtr() { return shared_from_this(); } -protected: +private: const std::string m_adapter_name; const bool m_is_software_adapter; const Feature::Mask m_supported_features; @@ -60,15 +58,20 @@ class DeviceBase class SystemBase : public System { public: - const Devices& GetGpuDevices() const override { return m_devices; } + const Ptrs& GetGpuDevices() const override { return m_devices; } Device::Feature::Mask GetGpuSupportedFeatures() const override { return m_supported_features; } - Device::Ptr GetNextGpuDevice(const Device& device) const override; - Device::Ptr GetSoftwareGpuDevice() const override; + Ptr GetNextGpuDevice(const Device& device) const override; + Ptr GetSoftwareGpuDevice() const override; std::string ToString() const noexcept override; protected: + void SetGpuSupportedFeatures(Device::Feature::Mask supported_features) { m_supported_features = supported_features; } + void ClearDevices() { m_devices.clear(); } + void AddDevice(Ptr&& sp_device) { m_devices.emplace_back(std::move(sp_device)); } + +private: Device::Feature::Mask m_supported_features = Device::Feature::Value::All; - Devices m_devices; + Ptrs m_devices; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/BlitCommandListDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/BlitCommandListDX.cpp new file mode 100644 index 000000000..bf8da753b --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/BlitCommandListDX.cpp @@ -0,0 +1,50 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/DirectX12/BlitCommandListDX.cpp +DirectX 12 implementation of the blit command list interface. + +******************************************************************************/ + +#include "BlitCommandListDX.h" + +#include +#include + +namespace Methane::Graphics +{ + +Ptr BlitCommandList::Create(CommandQueue& cmd_queue) +{ + ITT_FUNCTION_TASK(); + return std::make_shared(static_cast(cmd_queue)); +} + +BlitCommandListDX::BlitCommandListDX(CommandQueueBase& cmd_buffer) + : CommandListDX(cmd_buffer, Type::Blit) +{ + ITT_FUNCTION_TASK(); +} + +void BlitCommandListDX::Reset(const std::string& debug_group) +{ + ITT_FUNCTION_TASK(); + CommandListDX::Reset(debug_group); +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/BlitCommandListDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/BlitCommandListDX.h new file mode 100644 index 000000000..4c42e53d3 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/BlitCommandListDX.h @@ -0,0 +1,44 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/DirectX12/BlitCommandListDX.h +DirectX 12 implementation of the blit command list interface. + +******************************************************************************/ + +#pragma once + +#include "CommandListDX.hpp" + +#include + +namespace Methane::Graphics +{ + +class BlitCommandListDX final + : public CommandListDX + , public BlitCommandList +{ +public: + BlitCommandListDX(CommandQueueBase& cmd_buffer); + + // BlitCommandList interface + void Reset(const std::string& debug_group = "") override; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/BufferDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/BufferDX.cpp index 12f16f620..87c33c4e8 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/BufferDX.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/BufferDX.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,30 +22,30 @@ DirectX 12 implementation of the buffer interface. ******************************************************************************/ #include "BufferDX.h" -#include "ContextDX.h" #include "DeviceDX.h" #include "TypesDX.h" -#include +#include +#include namespace Methane::Graphics { -Buffer::Ptr Buffer::CreateVertexBuffer(Context& context, Data::Size size, Data::Size stride) +Ptr Buffer::CreateVertexBuffer(Context& context, Data::Size size, Data::Size stride) { ITT_FUNCTION_TASK(); const Buffer::Settings settings = { Buffer::Type::Vertex, Usage::Unknown, size }; - return std::make_shared(static_cast(context), settings, DescriptorByUsage(), stride); + return std::make_shared(dynamic_cast(context), settings, DescriptorByUsage(), stride); } -Buffer::Ptr Buffer::CreateIndexBuffer(Context& context, Data::Size size, PixelFormat format) +Ptr Buffer::CreateIndexBuffer(Context& context, Data::Size size, PixelFormat format) { ITT_FUNCTION_TASK(); const Buffer::Settings settings = { Buffer::Type::Index, Usage::Unknown, size }; - return std::make_shared(static_cast(context), settings, DescriptorByUsage(), format); + return std::make_shared(dynamic_cast(context), settings, DescriptorByUsage(), format); } -Buffer::Ptr Buffer::CreateConstantBuffer(Context& context, Data::Size size, bool addressable, const DescriptorByUsage& descriptor_by_usage) +Ptr Buffer::CreateConstantBuffer(Context& context, Data::Size size, bool addressable, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); Usage::Mask usage_mask = Usage::ShaderRead; @@ -53,7 +53,7 @@ Buffer::Ptr Buffer::CreateConstantBuffer(Context& context, Data::Size size, bool usage_mask |= Usage::Addressable; const Buffer::Settings settings = { Buffer::Type::Constant, usage_mask, size }; - return std::make_shared(static_cast(context), settings, descriptor_by_usage); + return std::make_shared(dynamic_cast(context), settings, descriptor_by_usage); } Data::Size Buffer::GetAlignedBufferSize(Data::Size size) noexcept @@ -93,14 +93,15 @@ void ConstantBufferDX::InitializeView() { ITT_FUNCTION_TASK(); - const Data::Size data_size = GetDataSize(); + const Data::Size data_size = GetDataSize(); m_buffer_view.BufferLocation = GetNativeGpuAddress(); m_buffer_view.SizeInBytes = static_cast(data_size); // NOTE: Addressable resources are bound to pipeline using GPU Address and byte offset - if (m_usage_mask & Usage::ShaderRead && !(m_usage_mask & Usage::Addressable)) + const Usage::Mask usage_mask = GetUsageMask(); + if (usage_mask & Usage::ShaderRead && !(usage_mask & Usage::Addressable)) { - D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle = GetNativeCPUDescriptorHandle(Usage::ShaderRead); + D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle = GetNativeCpuDescriptorHandle(Usage::ShaderRead); GetContextDX().GetDeviceDX().GetNativeDevice()->CreateConstantBufferView(&m_buffer_view, cpu_handle); } } diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/BufferDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/BufferDX.h index 77812f777..ee33a8941 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/BufferDX.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/BufferDX.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ DirectX 12 implementation of the buffer interface. #include #include #include -#include +#include #include #include @@ -35,7 +35,7 @@ namespace Methane::Graphics { template -class BufferDX : public BufferBase +class BufferDX final : public BufferBase { public: BufferDX(ContextBase& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage, ExtraViewArgs... view_args) @@ -55,15 +55,15 @@ class BufferDX : public BufferBase for(const SubResource& sub_resource : sub_resources) { - assert(!!m_cp_resource); + ID3D12Resource& d3d12_resource = GetNativeResourceRef(); char* p_resource_data = nullptr; CD3DX12_RANGE read_range(0, 0); // Zero range, since we're not going to read this resource on CPU - ThrowIfFailed(m_cp_resource->Map(sub_resource.GetRawIndex(), &read_range, reinterpret_cast(&p_resource_data))); + ThrowIfFailed(d3d12_resource.Map(sub_resource.GetRawIndex(), &read_range, reinterpret_cast(&p_resource_data))); assert(!!p_resource_data); std::copy(sub_resource.p_data, sub_resource.p_data + sub_resource.data_size, stdext::checked_array_iterator(p_resource_data, GetDataSize())); - m_cp_resource->Unmap(sub_resource.GetRawIndex(), nullptr); + d3d12_resource.Unmap(sub_resource.GetRawIndex(), nullptr); } } @@ -75,6 +75,7 @@ class BufferDX : public BufferBase protected: void InitializeView(ExtraViewArgs...); +private: // NOTE: in case of resource context placed in descriptor heap, m_buffer_view field holds context descriptor instead of context TViewNative m_buffer_view; uint32_t m_formatted_items_count = 0; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/CommandListDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/CommandListDX.h new file mode 100644 index 000000000..773b85166 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/CommandListDX.h @@ -0,0 +1,45 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/DirectX12/CommandListDX.h +DirectX 12 command list accessor interface for template class CommandListDX + +******************************************************************************/ + +#pragma once + +#include +#include + +namespace Methane::Graphics +{ + +namespace wrl = Microsoft::WRL; + +class CommandQueueDX; + +struct ICommandListDX +{ + virtual CommandQueueDX& GetCommandQueueDX() = 0; + virtual ID3D12GraphicsCommandList& GetNativeCommandList() const = 0; + virtual ID3D12GraphicsCommandList4* GetNativeCommandList4() const = 0; + + virtual ~ICommandListDX() = default; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/CommandListDX.hpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/CommandListDX.hpp new file mode 100644 index 000000000..debf67ba3 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/CommandListDX.hpp @@ -0,0 +1,184 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/DirectX12/CommandListDX.hpp +DirectX 12 base template implementation of the command list interface. + +******************************************************************************/ + +#pragma once + +#include "CommandListDX.h" +#include "DeviceDX.h" +#include "ContextDX.h" +#include "ResourceDX.h" +#include "CommandQueueDX.h" + +#include +#include + +#include +#include +#include +#include + +#include + +namespace Methane::Graphics +{ + +namespace wrl = Microsoft::WRL; + +class CommandQueueDX; +class RenderPassDX; + +template>> +class CommandListDX + : public CommandListBaseT + , public ICommandListDX +{ +public: + template + explicit CommandListDX(ConstructArgs&&... construct_args) + : CommandListBaseT(std::forward(construct_args)...) + { + ITT_FUNCTION_TASK(); + + const wrl::ComPtr& cp_device = GetCommandQueueDX().GetContextDX().GetDeviceDX().GetNativeDevice(); + assert(!!cp_device); + + ThrowIfFailed(cp_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_cp_command_allocator))); + ThrowIfFailed(cp_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_cp_command_allocator.Get(), nullptr, IID_PPV_ARGS(&m_cp_command_list))); + m_cp_command_list.As(&m_cp_command_list_4); + } + + // CommandList interface + + void PushDebugGroup(const std::string& name) override + { + ITT_FUNCTION_TASK(); + PIXBeginEvent(m_cp_command_list.Get(), 0, nowide::widen(name).c_str()); + } + + void PopDebugGroup() override + { + ITT_FUNCTION_TASK(); + PIXEndEvent(m_cp_command_list.Get()); + } + + void Commit() override + { + ITT_FUNCTION_TASK(); + + CommandListBaseT::Commit(); + + m_cp_command_list->Close(); + m_is_committed = true; + } + + // CommandListBase interface + + void SetResourceBarriers(const ResourceBase::Barriers& resource_barriers) override + { + ITT_FUNCTION_TASK(); + + if (resource_barriers.empty()) + return; + + std::vector dx_resource_barriers; + for (const ResourceBase::Barrier& resource_barrier : resource_barriers) + { + dx_resource_barriers.push_back(ResourceDX::GetNativeResourceBarrier(resource_barrier)); + } + + assert(m_cp_command_list); + m_cp_command_list->ResourceBarrier(static_cast(dx_resource_barriers.size()), dx_resource_barriers.data()); + } + + void Execute(uint32_t frame_index) override + { + ITT_FUNCTION_TASK(); + CommandListBaseT::Execute(frame_index); + + // NOTE: In DirectX there's no need for tracking command list completion, so it's completed right away + CommandListBaseT::Complete(frame_index); + } + + // CommandList interface + + void Reset(const std::string& debug_group) override + { + ITT_FUNCTION_TASK(); + if (!m_is_committed) + return; + + m_is_committed = false; + + ThrowIfFailed(m_cp_command_allocator->Reset()); + ThrowIfFailed(m_cp_command_list->Reset(m_cp_command_allocator.Get(), nullptr)); + + CommandListBase::Reset(debug_group); + } + + // Object interface + void SetName(const std::string& name) override + { + ITT_FUNCTION_TASK(); + + assert(m_cp_command_list); + m_cp_command_list->SetName(nowide::widen(name).c_str()); + + assert(m_cp_command_allocator); + m_cp_command_allocator->SetName(nowide::widen(name + " allocator").c_str()); + + CommandListBaseT::SetName(name); + } + + // ICommandListDX interface + CommandQueueDX& GetCommandQueueDX() override { return static_cast(GetCommandQueueBase()); } + ID3D12GraphicsCommandList& GetNativeCommandList() const override + { + assert(!!m_cp_command_list); + return *m_cp_command_list.Get(); + } + ID3D12GraphicsCommandList4* GetNativeCommandList4() const override { return m_cp_command_list_4.Get(); } + +protected: + bool IsCommitted() const { return m_is_committed; } + void SetCommitted(bool is_committed) { m_is_committed = is_committed; } + + ID3D12CommandAllocator& GetNativeCommandAllocatorRef() + { + assert(!!m_cp_command_allocator); + return *m_cp_command_allocator.Get(); + } + + ID3D12GraphicsCommandList& GetNativeCommandListRef() + { + assert(!!m_cp_command_list); + return *m_cp_command_list.Get(); + } + +private: + wrl::ComPtr m_cp_command_allocator; + wrl::ComPtr m_cp_command_list; + wrl::ComPtr m_cp_command_list_4; // extended interface for the same command list (may be unavailable on older Windows) + bool m_is_committed = false; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/CommandQueueDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/CommandQueueDX.cpp index c6e7bc113..a1524ba4e 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/CommandQueueDX.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/CommandQueueDX.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,29 +22,29 @@ DirectX 12 implementation of the command queue interface. ******************************************************************************/ #include "CommandQueueDX.h" -#include "ContextDX.h" #include "DeviceDX.h" +#include "BlitCommandListDX.h" #include "RenderCommandListDX.h" #include "ParallelRenderCommandListDX.h" -#include +#include +#include #include #include - #include namespace Methane::Graphics { -CommandQueue::Ptr CommandQueue::Create(Context& context) +Ptr CommandQueue::Create(Context& context) { ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context)); + return std::make_shared(dynamic_cast(context)); } CommandQueueDX::CommandQueueDX(ContextBase& context) - : CommandQueueBase(context, false) + : CommandQueueBase(context) { ITT_FUNCTION_TASK(); @@ -66,7 +66,7 @@ void CommandQueueDX::SetName(const std::string& name) m_cp_command_queue->SetName(nowide::widen(name).c_str()); } -void CommandQueueDX::Execute(const CommandList::Refs& command_lists) +void CommandQueueDX::Execute(const Refs& command_lists) { ITT_FUNCTION_TASK(); assert(!command_lists.empty()); @@ -79,22 +79,27 @@ void CommandQueueDX::Execute(const CommandList::Refs& command_lists) m_cp_command_queue->ExecuteCommandLists(static_cast(dx_command_lists.size()), dx_command_lists.data()); } -CommandQueueDX::D3D12CommandLists CommandQueueDX::GetNativeCommandLists(const CommandList::Refs& command_list_refs) +CommandQueueDX::D3D12CommandLists CommandQueueDX::GetNativeCommandLists(const Refs& command_list_refs) { ITT_FUNCTION_TASK(); D3D12CommandLists dx_command_lists; dx_command_lists.reserve(command_list_refs.size()); - for (const CommandList::Ref& command_list_ref : command_list_refs) + for (const Ref& command_list_ref : command_list_refs) { CommandListBase& command_list = dynamic_cast(command_list_ref.get()); switch (command_list.GetType()) { - case CommandList::Type::RenderCommandList: + case CommandList::Type::Blit: + { + dx_command_lists.push_back(&static_cast(command_list).GetNativeCommandList()); + } break; + + case CommandList::Type::Render: { - dx_command_lists.push_back(static_cast(command_list).GetNativeCommandList().Get()); + dx_command_lists.push_back(&static_cast(command_list).GetNativeCommandList()); } break; - case CommandList::Type::ParallelRenderCommandList: + case CommandList::Type::ParallelRender: { const D3D12CommandLists dx_parallel_command_lists = static_cast(command_list).GetNativeCommandLists(); dx_command_lists.insert(dx_command_lists.end(), dx_parallel_command_lists.begin(), dx_parallel_command_lists.end()); @@ -104,10 +109,17 @@ CommandQueueDX::D3D12CommandLists CommandQueueDX::GetNativeCommandLists(const Co return dx_command_lists; } -ContextDX& CommandQueueDX::GetContextDX() +IContextDX& CommandQueueDX::GetContextDX() noexcept +{ + ITT_FUNCTION_TASK(); + return static_cast(GetContext()); +} + +ID3D12CommandQueue& CommandQueueDX::GetNativeCommandQueue() { ITT_FUNCTION_TASK(); - return static_cast(m_context); + assert(!!m_cp_command_queue); + return *m_cp_command_queue.Get(); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/CommandQueueDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/CommandQueueDX.h index ec1a595b8..77bdb3a81 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/CommandQueueDX.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/CommandQueueDX.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -35,7 +35,7 @@ namespace Methane::Graphics namespace wrl = Microsoft::WRL; -class ContextDX; +struct IContextDX; class RenderStateBase; class CommandQueueDX final : public CommandQueueBase @@ -44,19 +44,19 @@ class CommandQueueDX final : public CommandQueueBase CommandQueueDX(ContextBase& context); // CommandQueue interface - void Execute(const CommandList::Refs& command_lists) override; + void Execute(const Refs& command_lists) override; // Object interface void SetName(const std::string& name) override; - ContextDX& GetContextDX(); - - wrl::ComPtr& GetNativeCommandQueue() { return m_cp_command_queue; } + IContextDX& GetContextDX() noexcept; + ID3D12CommandQueue& GetNativeCommandQueue(); protected: using D3D12CommandLists = std::vector; - static D3D12CommandLists GetNativeCommandLists(const CommandList::Refs& command_list_refs); + static D3D12CommandLists GetNativeCommandLists(const Refs& command_list_refs); +private: wrl::ComPtr m_cp_command_queue; }; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ContextDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ContextDX.cpp deleted file mode 100644 index 29707499c..000000000 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ContextDX.cpp +++ /dev/null @@ -1,402 +0,0 @@ -/****************************************************************************** - -Copyright 2019 Evgeny Gorodetskiy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -******************************************************************************* - -FILE: Methane/Graphics/DirectX12/ContextDX.cpp -DirectX 12 implementation of the context interface. - -******************************************************************************/ - -#include "ContextDX.h" -#include "DeviceDX.h" -#include "RenderStateDX.h" -#include "CommandQueueDX.h" -#include "TypesDX.h" - -#include -#include -#include - -#ifdef COMMAND_EXECUTION_LOGGING -#include -#endif - -#include -#include -#include - -namespace Methane::Graphics -{ - -static void SetWindowTopMostFlag(HWND window_handle, bool is_top_most) -{ - ITT_FUNCTION_TASK(); - - RECT window_rect = {}; - GetWindowRect(window_handle, &window_rect); - - const HWND window_position = is_top_most ? HWND_TOPMOST : HWND_NOTOPMOST; - SetWindowPos(window_handle, window_position, - window_rect.left, window_rect.top, - window_rect.right - window_rect.left, - window_rect.bottom - window_rect.top, - SWP_FRAMECHANGED | SWP_NOACTIVATE); -} - -static float GetDeviceScaleRatio(DEVICE_SCALE_FACTOR device_scale_factor) -{ - ITT_FUNCTION_TASK(); - - switch (device_scale_factor) - { - case SCALE_100_PERCENT: return 1.0f; - case SCALE_120_PERCENT: return 1.2f; - case SCALE_125_PERCENT: return 1.25f; - case SCALE_140_PERCENT: return 1.4f; - case SCALE_150_PERCENT: return 1.5f; - case SCALE_160_PERCENT: return 1.6f; - case SCALE_175_PERCENT: return 1.75f; - case SCALE_180_PERCENT: return 1.8f; - case SCALE_200_PERCENT: return 2.f; - case SCALE_225_PERCENT: return 2.25f; - case SCALE_250_PERCENT: return 2.5f; - case SCALE_300_PERCENT: return 3.f; - case SCALE_350_PERCENT: return 3.5f; - case SCALE_400_PERCENT: return 4.f; - case SCALE_450_PERCENT: return 4.5f; - case SCALE_500_PERCENT: return 5.f; - default: assert(0); - } - - return 1.f; -} - -Context::Ptr Context::Create(const Platform::AppEnvironment& env, Device& device, const Context::Settings& settings) -{ - ITT_FUNCTION_TASK(); - return std::make_shared(env, static_cast(device), settings); -} - -ContextDX::ContextDX(const Platform::AppEnvironment& env, DeviceBase& device, const Context::Settings& settings) - : ContextBase(device, settings) - , m_platform_env(env) -{ - ITT_FUNCTION_TASK(); - Initialize(device, true); -} - -ContextDX::~ContextDX() -{ - ITT_FUNCTION_TASK(); -} - -void ContextDX::Release() -{ - ITT_FUNCTION_TASK(); - - m_cp_swap_chain.Reset(); - m_sp_upload_fence.reset(); - m_sp_render_fence.reset(); - m_frame_fences.clear(); - - if (m_sp_device) - { - static_cast(*m_sp_device).ReleaseNativeDevice(); - m_sp_device.reset(); - } - - ContextBase::Release(); - - static_cast(System::Get()).ReportLiveObjects(); -} - -void ContextDX::Initialize(Device& device, bool deferred_heap_allocation) -{ - ITT_FUNCTION_TASK(); - - m_sp_device = static_cast(device).GetPtr(); - - // DXGI does not allow creating a swapchain targeting a window which has fullscreen styles(no border + topmost) - if (m_settings.is_full_screen) - { - // Temporary remove top-most flag and restore it when swap-chain is created - SetWindowTopMostFlag(m_platform_env.window_handle, false); - } - - // Initialize swap-chain - - DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {}; - swap_chain_desc.Width = m_settings.frame_size.width; - swap_chain_desc.Height = m_settings.frame_size.height; - swap_chain_desc.Format = TypeConverterDX::DataFormatToDXGI(m_settings.color_format); - swap_chain_desc.BufferCount = m_settings.frame_buffers_count; - swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - swap_chain_desc.SampleDesc.Count = 1; - - const wrl::ComPtr& cp_dxgi_factory = SystemDX::Get().GetNativeFactory(); - assert(!!cp_dxgi_factory); - - BOOL present_tearing_suport = FALSE; - ThrowIfFailed(cp_dxgi_factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &present_tearing_suport, sizeof(present_tearing_suport))); - if (present_tearing_suport) - { - swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; - } - - wrl::ComPtr& cp_command_queue = GetRenderCommandQueueDX().GetNativeCommandQueue(); - assert(!!cp_command_queue); - - wrl::ComPtr cp_swap_chain; - ThrowIfFailed(cp_dxgi_factory->CreateSwapChainForHwnd(cp_command_queue.Get(), m_platform_env.window_handle, &swap_chain_desc, NULL, NULL, &cp_swap_chain)); - assert(!!cp_swap_chain); - - if (m_settings.is_full_screen) - { - // Restore top-most flag - SetWindowTopMostFlag(m_platform_env.window_handle, true); - } - - ThrowIfFailed(cp_swap_chain.As(&m_cp_swap_chain)); - - // With tearing support enabled we will handle ALT+Enter key presses in the window message loop rather than let DXGI handle it by calling SetFullscreenState - ThrowIfFailed(cp_dxgi_factory->MakeWindowAssociation(m_platform_env.window_handle, DXGI_MWA_NO_ALT_ENTER)); - - // Initialize frame fences - - assert(!!m_cp_swap_chain); - m_frame_buffer_index = m_cp_swap_chain->GetCurrentBackBufferIndex(); - - const wrl::ComPtr& cp_device = static_cast(device).GetNativeDevice(); - assert(!!cp_device); - - m_frame_fences.clear(); - for (uint32_t frame_index = 0; frame_index < m_settings.frame_buffers_count; ++frame_index) - { - m_frame_fences.emplace_back(std::make_unique(GetRenderCommandQueueDX(), frame_index)); - } - - m_sp_render_fence = std::make_unique(GetRenderCommandQueueDX()); - m_sp_upload_fence = std::make_unique(GetUploadCommandQueueDX()); - - SetName(GetName()); - - ContextBase::Initialize(device, deferred_heap_allocation); -} - -void ContextDX::OnCommandQueueCompleted(CommandQueue& /*cmd_queue*/, uint32_t /*frame_index*/) -{ - ITT_FUNCTION_TASK(); -} - -void ContextDX::SetName(const std::string& name) -{ - ITT_FUNCTION_TASK(); - ContextBase::SetName(name); - - GetDevice().SetName(name + " Device"); - - for (FenceDX::Ptr& sp_frame_fence : m_frame_fences) - { - assert(!!sp_frame_fence); - sp_frame_fence->SetName(name + " Frame " + std::to_string(sp_frame_fence->GetFrame()) + " Fence"); - } - - m_sp_render_fence->SetName(name + " Render Fence"); - m_sp_upload_fence->SetName(name + " Upload Fence"); -} - -const DeviceDX& ContextDX::GetDeviceDX() const -{ - ITT_FUNCTION_TASK(); - return static_cast(GetDeviceBase()); -} - -void ContextDX::WaitForGpu(WaitFor wait_for) -{ - ITT_FUNCTION_TASK(); - - ContextBase::WaitForGpu(wait_for); - - switch (wait_for) - { - case WaitFor::ResourcesUploaded: - { - SCOPE_TIMER("ContextDX::WaitForGpu::ResourcesUploaded"); - assert(!!m_sp_upload_fence); - m_sp_upload_fence->Flush(); - } break; - - case WaitFor::RenderComplete: - { - SCOPE_TIMER("ContextDX::WaitForGpu::RenderComplete"); - assert(m_sp_render_fence); - m_sp_render_fence->Flush(); - } break; - - case WaitFor::FramePresented: - { - SCOPE_TIMER("ContextDX::WaitForGpu::FramePresented"); - GetCurrentFrameFence().Wait(); - } break; - } - - ContextBase::OnGpuWaitComplete(wait_for); -} - -void ContextDX::Resize(const FrameSize& frame_size) -{ - ITT_FUNCTION_TASK(); - - WaitForGpu(WaitFor::RenderComplete); - - ContextBase::Resize(frame_size); - - // Resize the swap chain to the desired dimensions - DXGI_SWAP_CHAIN_DESC1 desc = {}; - m_cp_swap_chain->GetDesc1(&desc); - ThrowIfFailed(m_cp_swap_chain->ResizeBuffers(m_settings.frame_buffers_count, frame_size.width, frame_size.height, desc.Format, desc.Flags)); - - m_frame_buffer_index = m_cp_swap_chain->GetCurrentBackBufferIndex(); -} - -void ContextDX::Present() -{ - ITT_FUNCTION_TASK(); - SCOPE_TIMER("ContextDX::Present"); - - ContextBase::Present(); - - // Preset frame to screen - const uint32_t present_flags = 0; // DXGI_PRESENT_DO_NOT_WAIT - const uint32_t vsync_interval = GetPresentVSyncInterval(); - - assert(m_cp_swap_chain); - ThrowIfFailed(m_cp_swap_chain->Present(vsync_interval, present_flags)); - - // Schedule a signal command in the queue for a currently finished frame - GetCurrentFrameFence().Signal(); - - OnCpuPresentComplete(); - - // Update current frame buffer index - m_frame_buffer_index = m_cp_swap_chain->GetCurrentBackBufferIndex(); -} - -float ContextDX::GetContentScalingFactor() const -{ - DEVICE_SCALE_FACTOR device_scale_factor = DEVICE_SCALE_FACTOR_INVALID; - HMONITOR monitor_handle = MonitorFromWindow(m_platform_env.window_handle, MONITOR_DEFAULTTONEAREST); - ThrowIfFailed(GetScaleFactorForMonitor(monitor_handle, &device_scale_factor)); - return GetDeviceScaleRatio(device_scale_factor); -} - -CommandQueueDX& ContextDX::GetUploadCommandQueueDX() -{ - ITT_FUNCTION_TASK(); - return static_cast(GetUploadCommandQueue()); -} - -CommandQueueDX& ContextDX::GetRenderCommandQueueDX() -{ - ITT_FUNCTION_TASK(); - return static_cast(GetRenderCommandQueue()); -} - -ContextDX::FenceDX& ContextDX::GetCurrentFrameFence() -{ - FenceDX::Ptr& sp_current_fence = GetCurrentFrameFencePtr(); - assert(!!sp_current_fence); - return *sp_current_fence; -} - -ContextDX::FenceDX::FenceDX(CommandQueueDX& command_queue, uint32_t frame) - : m_command_queue(command_queue) - , m_frame(frame) - , m_event(CreateEvent(nullptr, FALSE, FALSE, nullptr)) -{ - ITT_FUNCTION_TASK(); - if (!m_event) - { - ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); - } - - const wrl::ComPtr& cp_device = m_command_queue.GetContextDX().GetDeviceDX().GetNativeDevice(); - assert(!!cp_device); - - ThrowIfFailed(cp_device->CreateFence(m_value, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_cp_fence))); -} - -ContextDX::FenceDX::~FenceDX() -{ - ITT_FUNCTION_TASK(); - SafeCloseHandle(m_event); -} - -void ContextDX::FenceDX::Signal() -{ - ITT_FUNCTION_TASK(); - wrl::ComPtr& cp_command_queue = m_command_queue.GetNativeCommandQueue(); - assert(!!cp_command_queue); - assert(!!m_cp_fence); - - m_value++; - -#ifdef COMMAND_EXECUTION_LOGGING - Platform::PrintToDebugOutput("SIGNAL fence \"" + m_name + "\" with value " + std::to_string(m_value)); -#endif - - ThrowIfFailed(cp_command_queue->Signal(m_cp_fence.Get(), m_value)); -} - -void ContextDX::FenceDX::Wait() -{ - ITT_FUNCTION_TASK(); - assert(!!m_cp_fence); - assert(!!m_event); - -#ifdef COMMAND_EXECUTION_LOGGING - Platform::PrintToDebugOutput("WAIT fence \"" + m_name + "\" with value " + std::to_string(m_value)); -#endif - - if (m_cp_fence->GetCompletedValue() < m_value) - { - ThrowIfFailed(m_cp_fence->SetEventOnCompletion(m_value, m_event)); - WaitForSingleObjectEx(m_event, INFINITE, FALSE); - } -} - -void ContextDX::FenceDX::Flush() -{ - ITT_FUNCTION_TASK(); - Signal(); - Wait(); -} - -void ContextDX::FenceDX::SetName(const std::string& name) -{ - ITT_FUNCTION_TASK(); - if (m_name == name) - return; - - m_name = name; - - assert(!!m_cp_fence); - m_cp_fence->SetName(nowide::widen(name).c_str()); -} - -} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ContextDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ContextDX.h index fd6ce562b..ddd2c718f 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ContextDX.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ContextDX.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,96 +16,25 @@ limitations under the License. ******************************************************************************* -FILE: Methane/Graphics/DirectX12/ContextDX.cpp -DirectX 12 implementation of the context interface. +FILE: Methane/Graphics/DirectX12/ContextDX.h +DirectX 12 context accessor interface for template class ContextDX ******************************************************************************/ #pragma once -#include - -#include -#include -#include -#include - -#include - namespace Methane::Graphics { -namespace wrl = Microsoft::WRL; - -struct AppEnvironment; class CommandQueueDX; -class DeviceBase; class DeviceDX; -class ContextDX final : public ContextBase +struct IContextDX { -public: - ContextDX(const Platform::AppEnvironment& env, DeviceBase& device, const Settings& settings); - ~ContextDX() override; - - // Context interface - bool ReadyToRender() const override { return true; } - void WaitForGpu(WaitFor wait_for) override; - void Resize(const FrameSize& frame_size) override; - void Present() override; - Platform::AppView GetAppView() const override { return { nullptr }; } - float GetContentScalingFactor() const override; - - // ContextBase interface - void OnCommandQueueCompleted(CommandQueue& cmd_list, uint32_t frame_index) override; - - // Object interface - void SetName(const std::string& name) override; - - const DeviceDX& GetDeviceDX() const; - CommandQueueDX& GetUploadCommandQueueDX(); - CommandQueueDX& GetRenderCommandQueueDX(); - - const wrl::ComPtr& GetNativeSwapChain() const { return m_cp_swap_chain; } - -protected: - class FenceDX - { - public: - using Ptr = std::unique_ptr; - FenceDX(CommandQueueDX& command_queue, uint32_t frame = static_cast(-1)); - ~FenceDX(); - - void Signal(); - void Wait(); - void Flush(); - - uint32_t GetFrame() const { return m_frame; } - const std::string& GetName() const { return m_name; } - void SetName(const std::string& name); - - private: - CommandQueueDX& m_command_queue; - const uint32_t m_frame = 0; - uint64_t m_value = 0; - wrl::ComPtr m_cp_fence; - HANDLE m_event = nullptr; - std::string m_name; - }; - - FenceDX& GetCurrentFrameFence(); - inline FenceDX::Ptr& GetCurrentFrameFencePtr() { return m_frame_fences[m_frame_buffer_index]; } - inline uint32_t GetPresentVSyncInterval() const { return m_settings.vsync_enabled ? 1 : 0; } - - // ContextBase overrides - void Release() override; - void Initialize(Device& device, bool deferred_heap_allocation) override; + virtual const DeviceDX& GetDeviceDX() const noexcept = 0; + virtual CommandQueueDX& GetUploadCommandQueueDX() noexcept = 0; - const Platform::AppEnvironment m_platform_env; - wrl::ComPtr m_cp_swap_chain; - std::vector m_frame_fences; - FenceDX::Ptr m_sp_render_fence; - FenceDX::Ptr m_sp_upload_fence; + virtual ~IContextDX() = default; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ContextDX.hpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ContextDX.hpp new file mode 100644 index 000000000..9bd6f8329 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ContextDX.hpp @@ -0,0 +1,80 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/DirectX12/ContextDX.hpp +DirectX 12 base template implementation of the context interface. + +******************************************************************************/ + +#pragma once + +#include +#include "FenceDX.h" +#include "DeviceDX.h" +#include "CommandQueueDX.h" + +#include +#include + +#include +#include + +namespace Methane::Graphics +{ + +namespace wrl = Microsoft::WRL; + +template>> +class ContextDX : public ContextBaseT +{ +public: + ContextDX(DeviceBase& device, const typename ContextBaseT::Settings& settings) + : ContextBaseT(device, settings) + { + ITT_FUNCTION_TASK(); + } + + // ContextBase interface + + void Release() override + { + ITT_FUNCTION_TASK(); + GetMutableDeviceDX().ReleaseNativeDevice(); + ContextBaseT::Release(); + static_cast(System::Get()).ReportLiveObjects(); + } + + // Object interface + + void SetName(const std::string& name) override + { + ITT_FUNCTION_TASK(); + ContextBaseT::SetName(name); + GetDevice().SetName(name + " Device"); + } + + // IContextDX interface + + const DeviceDX& GetDeviceDX() const noexcept override { return static_cast(GetDeviceBase()); } + CommandQueueDX& GetUploadCommandQueueDX() noexcept override { return static_cast(GetUploadCommandQueue()); } + +protected: + DeviceDX& GetMutableDeviceDX() noexcept { return static_cast(GetDeviceBase()); } +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/DescriptorHeapDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/DescriptorHeapDX.cpp index e73a96eb3..fd96bdd2c 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/DescriptorHeapDX.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/DescriptorHeapDX.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,10 +22,10 @@ DirectX 12 implementation of the descriptor heap wrapper. ******************************************************************************/ #include "DescriptorHeapDX.h" -#include "ContextDX.h" #include "DeviceDX.h" -#include +#include +#include #include #include @@ -47,7 +47,7 @@ static D3D12_DESCRIPTOR_HEAP_TYPE GetNativeHeapType(DescriptorHeap::Type type) n return D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; } -DescriptorHeap::Ptr DescriptorHeap::Create(ContextBase& context, const Settings& settings) +Ptr DescriptorHeap::Create(ContextBase& context, const Settings& settings) { ITT_FUNCTION_TASK(); return std::make_shared(context, settings); @@ -70,7 +70,7 @@ DescriptorHeapDX::~DescriptorHeapDX() ITT_FUNCTION_TASK(); } -D3D12_CPU_DESCRIPTOR_HANDLE DescriptorHeapDX::GetNativeCPUDescriptorHandle(uint32_t descriptor_index) const noexcept +D3D12_CPU_DESCRIPTOR_HANDLE DescriptorHeapDX::GetNativeCpuDescriptorHandle(uint32_t descriptor_index) const noexcept { ITT_FUNCTION_TASK(); assert(!!m_cp_descriptor_heap); @@ -78,7 +78,7 @@ D3D12_CPU_DESCRIPTOR_HANDLE DescriptorHeapDX::GetNativeCPUDescriptorHandle(uint3 return CD3DX12_CPU_DESCRIPTOR_HANDLE(m_cp_descriptor_heap->GetCPUDescriptorHandleForHeapStart(), descriptor_index, m_descriptor_size); } -D3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeapDX::GetNativeGPUDescriptorHandle(uint32_t descriptor_index) const noexcept +D3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeapDX::GetNativeGpuDescriptorHandle(uint32_t descriptor_index) const noexcept { ITT_FUNCTION_TASK(); assert(!!m_cp_descriptor_heap); @@ -116,10 +116,10 @@ void DescriptorHeapDX::Allocate() DescriptorHeap::Allocate(); } -ContextDX& DescriptorHeapDX::GetContextDX() +IContextDX& DescriptorHeapDX::GetContextDX() noexcept { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(m_context); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/DescriptorHeapDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/DescriptorHeapDX.h index c31090355..e67c9d4d1 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/DescriptorHeapDX.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/DescriptorHeapDX.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -33,9 +33,9 @@ namespace Methane::Graphics namespace wrl = Microsoft::WRL; -class ContextDX; +struct IContextDX; -class DescriptorHeapDX : public DescriptorHeap +class DescriptorHeapDX final : public DescriptorHeap { public: DescriptorHeapDX(ContextBase& context, const Settings& settings); @@ -43,15 +43,16 @@ class DescriptorHeapDX : public DescriptorHeap ID3D12DescriptorHeap* GetNativeDescriptorHeap() noexcept { return m_cp_descriptor_heap.Get(); } D3D12_DESCRIPTOR_HEAP_TYPE GetNativeDescriptorHeapType() const noexcept { return m_descriptor_heap_type; } - D3D12_CPU_DESCRIPTOR_HANDLE GetNativeCPUDescriptorHandle(uint32_t descriptor_index) const noexcept; - D3D12_GPU_DESCRIPTOR_HANDLE GetNativeGPUDescriptorHandle(uint32_t descriptor_index) const noexcept; + D3D12_CPU_DESCRIPTOR_HANDLE GetNativeCpuDescriptorHandle(uint32_t descriptor_index) const noexcept; + D3D12_GPU_DESCRIPTOR_HANDLE GetNativeGpuDescriptorHandle(uint32_t descriptor_index) const noexcept; // DescriptorHeap interface void Allocate() override; protected: - ContextDX& GetContextDX(); + IContextDX& GetContextDX() noexcept; +private: D3D12_DESCRIPTOR_HEAP_TYPE m_descriptor_heap_type; uint32_t m_descriptor_size; wrl::ComPtr m_cp_descriptor_heap; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/DeviceDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/DeviceDX.cpp index da41f75b5..89a8481ce 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/DeviceDX.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/DeviceDX.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ DirectX 12 implementation of the device interface. #include "DeviceDX.h" -#include +#include #include #ifdef _DEBUG @@ -41,7 +41,7 @@ DirectX 12 implementation of the device interface. namespace Methane::Graphics { -static std::string GetAdapterNameDXGI(IDXGIAdapter& adapter) +static std::string GetAdapterNameDxgi(IDXGIAdapter& adapter) { ITT_FUNCTION_TASK(); @@ -50,7 +50,7 @@ static std::string GetAdapterNameDXGI(IDXGIAdapter& adapter) return nowide::narrow(desc.Description); } -static bool IsSoftwareAdapterDXGI(IDXGIAdapter1& adapter) +static bool IsSoftwareAdapterDxgi(IDXGIAdapter1& adapter) { ITT_FUNCTION_TASK(); @@ -66,9 +66,9 @@ Device::Feature::Mask DeviceDX::GetSupportedFeatures(const wrl::ComPtr& cp_adapter, D3D_FEATURE_LEVEL feature_level) - : DeviceBase(GetAdapterNameDXGI(*cp_adapter.Get()), - IsSoftwareAdapterDXGI(static_cast(*cp_adapter.Get())), - GetSupportedFeatures(cp_adapter, feature_level)) + : DeviceBase(GetAdapterNameDxgi(*cp_adapter.Get()), + IsSoftwareAdapterDxgi(static_cast(*cp_adapter.Get())), + GetSupportedFeatures(cp_adapter, feature_level)) , m_cp_adapter(cp_adapter) , m_feature_level(feature_level) { @@ -137,8 +137,8 @@ SystemDX::~SystemDX() UnregisterAdapterChangeEvent(); m_cp_factory.Reset(); - m_devices.clear(); + ClearDevices(); ReportLiveObjects(); } @@ -216,15 +216,15 @@ void SystemDX::CheckForChanges() UnregisterAdapterChangeEvent(); Initialize(); - Devices prev_devices = m_devices; + Ptrs prev_devices = m_devices; UpdateGpuDevices(m_supported_features); - for (const Device::Ptr& sp_prev_device : prev_devices) + for (const Ptr& sp_prev_device : prev_devices) { assert(!!sp_prev_device); DeviceDX& prev_device = static_cast(*sp_prev_device); auto device_it = std::find_if(m_devices.begin(), m_devices.end(), - [prev_device](const Device::Ptr& sp_device) + [prev_device](const Ptr& sp_device) { DeviceDX& device = static_cast(*sp_device); return prev_device.GetNativeAdapter().GetAddressOf() == device.GetNativeAdapter().GetAddressOf(); @@ -238,14 +238,14 @@ void SystemDX::CheckForChanges() #endif } -const Devices& SystemDX::UpdateGpuDevices(Device::Feature::Mask supported_features) +const Ptrs& SystemDX::UpdateGpuDevices(Device::Feature::Mask supported_features) { ITT_FUNCTION_TASK(); assert(m_cp_factory); const D3D_FEATURE_LEVEL dx_feature_level = D3D_FEATURE_LEVEL_11_0; - m_supported_features = supported_features; - m_devices.clear(); + SetGpuSupportedFeatures(supported_features); + ClearDevices(); IDXGIAdapter1* p_adapter = nullptr; for (UINT adapter_index = 0; DXGI_ERROR_NOT_FOUND != m_cp_factory->EnumAdapters1(adapter_index, &p_adapter); ++adapter_index) @@ -256,7 +256,7 @@ const Devices& SystemDX::UpdateGpuDevices(Device::Feature::Mask supported_featur // Don't select the Basic Render Driver adapter. // If you want a software adapter, pass in "/warp" on the command line. - if (IsSoftwareAdapterDXGI(*p_adapter)) + if (IsSoftwareAdapterDxgi(*p_adapter)) continue; AddDevice(p_adapter, dx_feature_level); @@ -269,7 +269,7 @@ const Devices& SystemDX::UpdateGpuDevices(Device::Feature::Mask supported_featur AddDevice(cp_warp_adapter, dx_feature_level); } - return m_devices; + return GetGpuDevices(); } void SystemDX::AddDevice(const wrl::ComPtr& cp_adapter, D3D_FEATURE_LEVEL feature_level) @@ -281,11 +281,10 @@ void SystemDX::AddDevice(const wrl::ComPtr& cp_adapter, D3D_FEATUR return; Device::Feature::Mask device_supported_features = DeviceDX::GetSupportedFeatures(cp_adapter, feature_level); - if (!(device_supported_features & m_supported_features)) + if (!(device_supported_features & GetGpuSupportedFeatures())) return; - Device::Ptr sp_device = std::make_shared(cp_adapter, feature_level); - m_devices.push_back(sp_device); + SystemBase::AddDevice(std::make_shared(cp_adapter, feature_level)); } void SystemDX::ReportLiveObjects() diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/DeviceDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/DeviceDX.h index 32b15ca8c..e18e3c355 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/DeviceDX.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/DeviceDX.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -70,8 +70,8 @@ class SystemDX final : public SystemBase ~SystemDX() override; // System interface - void CheckForChanges() override; - const Devices& UpdateGpuDevices(Device::Feature::Mask supported_features) override; + void CheckForChanges() override; + const Ptrs& UpdateGpuDevices(Device::Feature::Mask supported_features) override; const wrl::ComPtr& GetNativeFactory() { return m_cp_factory; } void ReportLiveObjects(); diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/FenceDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/FenceDX.cpp new file mode 100644 index 000000000..a348fe80a --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/FenceDX.cpp @@ -0,0 +1,110 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/DirectX12/FenceDX.cpp +DirectX 12 fence implementation. + +******************************************************************************/ + +#include "FenceDX.h" +#include "CommandQueueDX.h" +#include "DeviceDX.h" + +#include +#include +#include + +#include +#include + +namespace Methane::Graphics +{ + +UniquePtr Fence::Create(CommandQueue& command_queue) +{ + ITT_FUNCTION_TASK(); + return std::make_unique(static_cast(command_queue)); +} + +FenceDX::FenceDX(CommandQueueBase& command_queue) + : FenceBase(command_queue) + , m_event(CreateEvent(nullptr, FALSE, FALSE, nullptr)) +{ + ITT_FUNCTION_TASK(); + if (!m_event) + { + ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); + } + + const wrl::ComPtr& cp_device = GetCommandQueueDX().GetContextDX().GetDeviceDX().GetNativeDevice(); + assert(!!cp_device); + + ThrowIfFailed(cp_device->CreateFence(GetValue(), D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_cp_fence))); +} + +FenceDX::~FenceDX() +{ + ITT_FUNCTION_TASK(); + SafeCloseHandle(m_event); +} + +void FenceDX::Signal() +{ + ITT_FUNCTION_TASK(); + + FenceBase::Signal(); + + assert(!!m_cp_fence); + ID3D12CommandQueue& dx_command_queue = GetCommandQueueDX().GetNativeCommandQueue(); + ThrowIfFailed(dx_command_queue.Signal(m_cp_fence.Get(), GetValue())); +} + +void FenceDX::Wait() +{ + ITT_FUNCTION_TASK(); + + FenceBase::Wait(); + + assert(!!m_cp_fence); + assert(!!m_event); + if (m_cp_fence->GetCompletedValue() < GetValue()) + { + ThrowIfFailed(m_cp_fence->SetEventOnCompletion(GetValue(), m_event)); + WaitForSingleObjectEx(m_event, INFINITE, FALSE); + } +} + +void FenceDX::SetName(const std::string& name) noexcept +{ + ITT_FUNCTION_TASK(); + if (ObjectBase::GetName() == name) + return; + + ObjectBase::SetName(name); + + assert(!!m_cp_fence); + m_cp_fence->SetName(nowide::widen(name).c_str()); +} + +CommandQueueDX& FenceDX::GetCommandQueueDX() +{ + ITT_FUNCTION_TASK(); + return static_cast(GetCommandQueue()); +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/FenceDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/FenceDX.h new file mode 100644 index 000000000..1e6fcb8a5 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/FenceDX.h @@ -0,0 +1,58 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/DirectX12/FenceDX.h +DirectX 12 fence implementation. + +******************************************************************************/ + +#pragma once + +#include + +#include +#include + +namespace Methane::Graphics +{ + +namespace wrl = Microsoft::WRL; + +class CommandQueueDX; + +class FenceDX final : public FenceBase +{ +public: + FenceDX(CommandQueueBase& command_queue); + ~FenceDX(); + + // Fence overrides + void Signal() override; + void Wait() override; + + // Object override + void SetName(const std::string& name) noexcept override; + +private: + CommandQueueDX& GetCommandQueueDX(); + + wrl::ComPtr m_cp_fence; + HANDLE m_event = nullptr; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ParallelRenderCommandListDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ParallelRenderCommandListDX.cpp index 947d910a3..36deb67e0 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ParallelRenderCommandListDX.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ParallelRenderCommandListDX.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,10 +25,10 @@ DirectX 12 implementation of the parallel render command list interface. #include "RenderStateDX.h" #include "RenderPassDX.h" #include "CommandQueueDX.h" -#include "ContextDX.h" #include "DeviceDX.h" -#include +#include +#include #include #include @@ -46,7 +46,7 @@ static std::string GetTrailingCommandListDebugName(const std::string& base_name, return GetParallelCommandListDebugName(base_name, is_beginning ? "[Beginning]" : "[Ending]"); } -ParallelRenderCommandList::Ptr ParallelRenderCommandList::Create(CommandQueue& cmd_queue, RenderPass& render_pass) +Ptr ParallelRenderCommandList::Create(CommandQueue& cmd_queue, RenderPass& render_pass) { ITT_FUNCTION_TASK(); return std::make_shared(static_cast(cmd_queue), static_cast(render_pass)); @@ -54,7 +54,7 @@ ParallelRenderCommandList::Ptr ParallelRenderCommandList::Create(CommandQueue& c ParallelRenderCommandListDX::ParallelRenderCommandListDX(CommandQueueBase& cmd_buffer, RenderPassBase& render_pass) : ParallelRenderCommandListBase(cmd_buffer, render_pass) - , m_begining_command_list(cmd_buffer, render_pass) + , m_beginning_command_list(cmd_buffer, render_pass) , m_ending_command_list(cmd_buffer, render_pass) { ITT_FUNCTION_TASK(); @@ -67,18 +67,26 @@ ParallelRenderCommandListDX::ParallelRenderCommandListDX(CommandQueueBase& cmd_b assert(!!cp_device); } -void ParallelRenderCommandListDX::Reset(const RenderState::Ptr& sp_render_state, const std::string& debug_group) +void ParallelRenderCommandListDX::Reset(const Ptr& sp_render_state, const std::string& debug_group) { ITT_FUNCTION_TASK(); // Render pass is begun in "beginning" command list only, // but it will be ended in the "ending" command list on commit of the parallel CL - m_begining_command_list.Reset(RenderState::Ptr(), debug_group); // begins render pass + m_beginning_command_list.Reset(Ptr(), debug_group); // begins render pass m_ending_command_list.ResetNative(); // only reset native command list // Instead of closing debug group (from Reset call) on beginning CL commit, we force to close it in ending CL - m_begining_command_list.SetDebugGroupOpened(false); - m_ending_command_list.SetDebugGroupOpened(true); + m_beginning_command_list.SetOpenDebugGroup(""); + m_ending_command_list.SetOpenDebugGroup(debug_group); + + if (sp_render_state) + { + // Initialize native pipeline state before resetting per-thread command lists + // to allow parallel reset of all CLs at once with using native pipeline state for each reset + RenderStateDX& dx_render_state = static_cast(*sp_render_state); + dx_render_state.InitializeNativePipelineState(); + } ParallelRenderCommandListBase::Reset(sp_render_state, debug_group); } @@ -87,29 +95,29 @@ void ParallelRenderCommandListDX::SetName(const std::string& name) { ITT_FUNCTION_TASK(); - m_begining_command_list.SetName(GetTrailingCommandListDebugName(name, true)); + m_beginning_command_list.SetName(GetTrailingCommandListDebugName(name, true)); m_ending_command_list.SetName(GetTrailingCommandListDebugName(name, false)); ParallelRenderCommandListBase::SetName(name); } -void ParallelRenderCommandListDX::Commit(bool present_drawable) +void ParallelRenderCommandListDX::Commit() { ITT_FUNCTION_TASK(); // Render pass was begun in "beginning" command list, // but it is ended in "ending" command list only - m_ending_command_list.Commit(false); // ends render pass - m_begining_command_list.Commit(false); + m_ending_command_list.Commit(); // ends render pass + m_beginning_command_list.Commit(); - ParallelRenderCommandListBase::Commit(present_drawable); + ParallelRenderCommandListBase::Commit(); } void ParallelRenderCommandListDX::Execute(uint32_t frame_index) { ITT_FUNCTION_TASK(); - m_begining_command_list.Execute(frame_index); + m_beginning_command_list.Execute(frame_index); ParallelRenderCommandListBase::Execute(frame_index); @@ -124,17 +132,18 @@ ParallelRenderCommandListDX::D3D12CommandLists ParallelRenderCommandListDX::GetN ITT_FUNCTION_TASK(); D3D12CommandLists dx_command_lists; - dx_command_lists.reserve(m_parallel_comand_lists.size() + 2); // 2 command lists reserved for beginning and ending - dx_command_lists.push_back(m_begining_command_list.GetNativeCommandList().Get()); + const Ptrs& parallel_command_lists = GetParallelCommandLists(); + dx_command_lists.reserve(parallel_command_lists.size() + 2); // 2 command lists reserved for beginning and ending + dx_command_lists.push_back(&m_beginning_command_list.GetNativeCommandList()); - for (const RenderCommandList::Ptr& sp_command_list : m_parallel_comand_lists) + for (const Ptr& sp_command_list : parallel_command_lists) { assert(!!sp_command_list); RenderCommandListDX& dx_command_list = static_cast(*sp_command_list); - dx_command_lists.push_back(dx_command_list.GetNativeCommandList().Get()); + dx_command_lists.push_back(&dx_command_list.GetNativeCommandList()); } - dx_command_lists.push_back(m_ending_command_list.GetNativeCommandList().Get()); + dx_command_lists.push_back(&m_ending_command_list.GetNativeCommandList()); return dx_command_lists; } diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ParallelRenderCommandListDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ParallelRenderCommandListDX.h index 68fc680e7..81328721b 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ParallelRenderCommandListDX.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ParallelRenderCommandListDX.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -39,10 +39,10 @@ class ParallelRenderCommandListDX final : public ParallelRenderCommandListBase ParallelRenderCommandListDX(CommandQueueBase& cmd_buffer, RenderPassBase& render_pass); // ParallelRenderCommandList interface - void Reset(const RenderState::Ptr& sp_render_state, const std::string& debug_group = "") override; + void Reset(const Ptr& sp_render_state, const std::string& debug_group = "") override; // CommandList interface - void Commit(bool present_drawable) override; + void Commit() override; // CommandListBase interface void Execute(uint32_t frame_index) override; @@ -53,11 +53,11 @@ class ParallelRenderCommandListDX final : public ParallelRenderCommandListBase using D3D12CommandLists = std::vector; D3D12CommandLists GetNativeCommandLists() const; -protected: +private: CommandQueueDX& GetCommandQueueDX(); RenderPassDX& GetPassDX(); - RenderCommandListDX m_begining_command_list; + RenderCommandListDX m_beginning_command_list; RenderCommandListDX m_ending_command_list; }; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ProgramBindingsDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ProgramBindingsDX.cpp new file mode 100644 index 000000000..b293142f2 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ProgramBindingsDX.cpp @@ -0,0 +1,437 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/DirectX12/ProgramBindingsDX.cpp +DirectX 12 implementation of the program bindings interface. + +******************************************************************************/ + +#include "ProgramBindingsDX.h" +#include "DeviceDX.h" +#include "ProgramDX.h" +#include "CommandListDX.h" +#include "DescriptorHeapDX.h" + +#include +#include +#include +#include + +#include +#include + +namespace Methane::Graphics +{ + +Ptr ProgramBindingsBase::ArgumentBindingBase::CreateCopy(const ArgumentBindingBase& other_argument_binding) +{ + ITT_FUNCTION_TASK(); + return std::make_shared(static_cast(other_argument_binding)); +} + +ProgramBindingsDX::ArgumentBindingDX::ArgumentBindingDX(const ContextBase& context, SettingsDX settings) + : ProgramBindingsBase::ArgumentBindingBase(context, settings) + , m_settings_dx(std::move(settings)) +{ + ITT_FUNCTION_TASK(); +} + +ProgramBindingsDX::ArgumentBindingDX::ArgumentBindingDX(const ArgumentBindingDX& other) + : ArgumentBindingBase(other) + , m_settings_dx(other.m_settings_dx) + , m_root_parameter_index(other.m_root_parameter_index) + , m_descriptor_range(other.m_descriptor_range) + , m_p_descriptor_heap_reservation(other.m_p_descriptor_heap_reservation) + , m_resource_locations_dx(other.m_resource_locations_dx) +{ + ITT_FUNCTION_TASK(); +} + +void ProgramBindingsDX::ArgumentBindingDX::SetResourceLocations(const Resource::Locations& resource_locations) +{ + ITT_FUNCTION_TASK(); + + ArgumentBindingBase::SetResourceLocations(resource_locations); + + m_resource_locations_dx.clear(); + + if (m_settings_dx.type == Type::DescriptorTable && + resource_locations.size() > m_descriptor_range.count) + { + throw std::invalid_argument("The number of bound resources (" + std::to_string(resource_locations.size()) + + ") exceeds reserved descriptors count (" + std::to_string(m_descriptor_range.count) + ")."); + } + + const uint32_t descriptor_range_start = m_p_descriptor_heap_reservation + ? m_p_descriptor_heap_reservation->GetRange(m_settings_dx.argument.IsConstant()).GetStart() + : std::numeric_limits::max(); + const DescriptorHeapDX* p_dx_descriptor_heap = m_p_descriptor_heap_reservation + ? static_cast(&m_p_descriptor_heap_reservation->heap.get()) + : nullptr; + const DescriptorHeap::Type descriptor_heap_type = p_dx_descriptor_heap + ? p_dx_descriptor_heap->GetSettings().type + : DescriptorHeap::Type::Undefined; + const D3D12_DESCRIPTOR_HEAP_TYPE native_heap_type = p_dx_descriptor_heap + ? p_dx_descriptor_heap->GetNativeDescriptorHeapType() + : D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + const wrl::ComPtr& cp_native_device = static_cast(GetContext()).GetDeviceDX().GetNativeDevice(); + assert(!!cp_native_device); + + uint32_t resource_index = 0; + m_resource_locations_dx.reserve(resource_locations.size()); + for(const Resource::Location& resource_location : resource_locations) + { + m_resource_locations_dx.emplace_back(resource_location); + + if (!m_p_descriptor_heap_reservation) + continue; + + const ResourceDX::LocationDX& dx_resource_location = m_resource_locations_dx.back(); + if (m_descriptor_range.heap_type != descriptor_heap_type) + { + throw std::logic_error("Incompatible heap type \"" + p_dx_descriptor_heap->GetTypeName() + + "\" is set for resource binding on argument \"" + m_settings_dx.argument.name + + "\" of \"" + Shader::GetTypeName(m_settings_dx.argument.shader_type) + "\" shader."); + } + + const uint32_t descriptor_index = descriptor_range_start + m_descriptor_range.offset + resource_index; + cp_native_device->CopyDescriptorsSimple( + 1, + p_dx_descriptor_heap->GetNativeCpuDescriptorHandle(descriptor_index), + dx_resource_location.GetResourceDX().GetNativeCpuDescriptorHandle(ResourceBase::Usage::ShaderRead), + native_heap_type + ); + + resource_index++; + } +} + +void ProgramBindingsDX::ArgumentBindingDX::SetDescriptorRange(const DescriptorRange& descriptor_range) +{ + ITT_FUNCTION_TASK(); + + const DescriptorHeap::Type expected_heap_type = GetDescriptorHeapType(); + if (descriptor_range.heap_type != expected_heap_type) + { + throw std::runtime_error("Descriptor heap type \"" + DescriptorHeap::GetTypeName(descriptor_range.heap_type) + + "\" is incompatible with the resource binding, expected heap type is \"" + + DescriptorHeap::GetTypeName(expected_heap_type) + "\"."); + } + if (descriptor_range.count < m_settings_dx.resource_count) + { + throw std::runtime_error("Descriptor range size (" + std::to_string(descriptor_range.count) + + ") will not fit bound shader resources (" + std::to_string(m_settings_dx.resource_count) + ")."); + } + m_descriptor_range = descriptor_range; +} + +Ptr ProgramBindings::Create(const Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument) +{ + ITT_FUNCTION_TASK(); + + std::shared_ptr sp_dx_program_bindings = std::make_shared(sp_program, resource_locations_by_argument); + sp_dx_program_bindings->Initialize(); // NOTE: Initialize is called externally (not from constructor) to enable using shared_from_this from its code + return sp_dx_program_bindings; +} + +Ptr ProgramBindings::CreateCopy(const ProgramBindings& other_program_bindings, const ResourceLocationsByArgument& replace_resource_locations_by_argument) +{ + ITT_FUNCTION_TASK(); + + std::shared_ptr sp_dx_program_bindings = std::make_shared(static_cast(other_program_bindings), replace_resource_locations_by_argument); + sp_dx_program_bindings->Initialize(); // NOTE: Initialize is called externally (not from constructor) to enable using shared_from_this from its code + return sp_dx_program_bindings; +} + +ProgramBindingsDX::ProgramBindingsDX(const Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument) + : ProgramBindingsBase(sp_program, resource_locations_by_argument) +{ + ITT_FUNCTION_TASK(); +} + +ProgramBindingsDX::ProgramBindingsDX(const ProgramBindingsDX& other_program_bindings, const ResourceLocationsByArgument& replace_resource_locations_by_argument) + : ProgramBindingsBase(other_program_bindings, replace_resource_locations_by_argument) +{ + ITT_FUNCTION_TASK(); +} + +void ProgramBindingsDX::Initialize() +{ + ITT_FUNCTION_TASK(); + + ResourceManager& resource_manager = static_cast(GetProgram()).GetContext().GetResourceManager(); + if (resource_manager.DeferredHeapAllocationEnabled()) + { + resource_manager.DeferProgramBindingsInitialization(*this); + } + else + { + CompleteInitialization(); + } +} + +void ProgramBindingsDX::CompleteInitialization() +{ + ITT_FUNCTION_TASK(); + + CopyDescriptorsToGpu(); + UpdateRootParameterBindings(); +} + +void ProgramBindingsDX::Apply(CommandListBase& command_list, ApplyBehavior::Mask apply_behavior) const +{ + ITT_FUNCTION_TASK(); + + using DXBindingType = ArgumentBindingDX::Type; + using DXDescriptorRange = ArgumentBindingDX::DescriptorRange; + + ICommandListDX& command_list_dx = dynamic_cast(command_list); + const ProgramBindingsBase* p_applied_program_bindings = command_list.GetProgramBindings(); + const bool apply_constant_resource_bindings = apply_behavior & ~ApplyBehavior::ConstantOnce || !p_applied_program_bindings; + + ID3D12GraphicsCommandList& d3d12_command_list = command_list_dx.GetNativeCommandList(); + + // Set resource transition barriers before applying resource bindings + if (apply_behavior & ApplyBehavior::StateBarriers) + { + ResourceBase::Barriers resource_transition_barriers = ApplyResourceStates(apply_constant_resource_bindings); + if (!resource_transition_barriers.empty()) + { + command_list.SetResourceBarriers(resource_transition_barriers); + } + } + + // Apply root parameter bindings after resource barriers + if (apply_constant_resource_bindings) + { + for (const RootParameterBinding& root_parameter_binding : m_constant_root_parameter_bindings) + { + ApplyRootParameterBinding(root_parameter_binding, d3d12_command_list); + } + } + + for(const RootParameterBinding& root_parameter_binding : m_variadic_root_parameter_bindings) + { + if (apply_behavior & ApplyBehavior::ChangesOnly && p_applied_program_bindings && + root_parameter_binding.argument_binding.IsAlreadyApplied(GetProgram(), *p_applied_program_bindings)) + continue; + + ApplyRootParameterBinding(root_parameter_binding, d3d12_command_list); + } +} + +void ProgramBindingsDX::ForEachArgumentBinding(const ArgumentBindingFunc& argument_binding_function) const +{ + ITT_FUNCTION_TASK(); + + for (auto& binding_by_argument : GetArgumentBindings()) + { + assert(!!binding_by_argument.second); + + ArgumentBindingDX& argument_binding = static_cast(*binding_by_argument.second); + const ArgumentBindingDX::DescriptorRange& descriptor_range = argument_binding.GetDescriptorRange(); + const DescriptorHeap::Reservation* p_heap_reservation = nullptr; + + if (descriptor_range.heap_type != DescriptorHeap::Type::Undefined) + { + const std::optional& descriptor_heap_reservation_opt = GetDescriptorHeapReservationByType(descriptor_range.heap_type); + if (descriptor_heap_reservation_opt) + { + p_heap_reservation = &*descriptor_heap_reservation_opt; + } + } + + argument_binding_function(argument_binding, p_heap_reservation); + } +} + +void ProgramBindingsDX::AddRootParameterBinding(const Program::ArgumentDesc& argument_desc, RootParameterBinding root_parameter_binding) +{ + ITT_FUNCTION_TASK(); + + if (argument_desc.IsConstant()) + { + m_constant_root_parameter_bindings.emplace_back(std::move(root_parameter_binding)); + } + else + { + m_variadic_root_parameter_bindings.emplace_back(std::move(root_parameter_binding)); + } +} + +void ProgramBindingsDX::AddResourceState(const Program::ArgumentDesc& argument_desc, ResourceState resource_state) +{ + ITT_FUNCTION_TASK(); + + if (argument_desc.IsConstant()) + { + m_constant_resource_states.emplace_back(std::move(resource_state)); + } + else + { + m_variadic_resource_states.emplace_back(std::move(resource_state)); + } +} + +void ProgramBindingsDX::UpdateRootParameterBindings() +{ + ITT_FUNCTION_TASK(); + + using DXBindingType = ArgumentBindingDX::Type; + using DXDescriptorRange = ArgumentBindingDX::DescriptorRange; + + ForEachArgumentBinding([this](ArgumentBindingDX& argument_binding, const DescriptorHeap::Reservation* p_heap_reservation) + { + const ArgumentBindingDX::SettingsDX binding_settings = argument_binding.GetSettingsDX(); + + if (binding_settings.type == DXBindingType::DescriptorTable) + { + if (!p_heap_reservation) + throw std::runtime_error("Descriptor heap reservation is not available for \"Descriptor Table\" resource binding."); + + const DescriptorHeapDX& dx_descriptor_heap = static_cast(p_heap_reservation->heap.get()); + const DXDescriptorRange& descriptor_range = argument_binding.GetDescriptorRange(); + const uint32_t descriptor_index = p_heap_reservation->GetRange(binding_settings.argument.IsConstant()).GetStart() + descriptor_range.offset; + + AddRootParameterBinding(binding_settings.argument, { + argument_binding, + argument_binding.GetRootParameterIndex(), + dx_descriptor_heap.GetNativeGpuDescriptorHandle(descriptor_index), + 0 + }); + } + + for (const ResourceDX::LocationDX& resource_location_dx : argument_binding.GetResourceLocationsDX()) + { + if (binding_settings.type == DXBindingType::ConstantBufferView || + binding_settings.type == DXBindingType::ShaderResourceView) + { + AddRootParameterBinding(binding_settings.argument, { + argument_binding, + argument_binding.GetRootParameterIndex(), + D3D12_GPU_DESCRIPTOR_HANDLE{}, + resource_location_dx.GetNativeGpuAddress() + }); + } + + const ResourceBase::State resource_state = binding_settings.argument.shader_type == Shader::Type::Pixel + ? ResourceBase::State::PixelShaderResource + : ResourceBase::State::NonPixelShaderResource; + AddResourceState(binding_settings.argument, { + std::dynamic_pointer_cast(resource_location_dx.GetResourcePtr()), + resource_state + }); + } + }); +} + +ResourceBase::Barriers ProgramBindingsDX::ApplyResourceStates(bool apply_constant_resource_states) const +{ + ITT_FUNCTION_TASK(); + + ResourceBase::Barriers resource_transition_barriers; + + if (apply_constant_resource_states) + { + for(const ResourceState& resource_state : m_constant_resource_states) + { + assert(!!resource_state.sp_resource); + resource_state.sp_resource->SetState(resource_state.state, resource_transition_barriers); + } + } + + for(const ResourceState& resource_state : m_variadic_resource_states) + { + assert(!!resource_state.sp_resource); + resource_state.sp_resource->SetState(resource_state.state, resource_transition_barriers); + } + + return resource_transition_barriers; +} + +void ProgramBindingsDX::ApplyRootParameterBinding(const RootParameterBinding& root_parameter_binding, ID3D12GraphicsCommandList& d3d12_command_list) const +{ + ITT_FUNCTION_TASK(); + + const ArgumentBindingDX::Type binding_type = root_parameter_binding.argument_binding.GetSettingsDX().type; + + switch (binding_type) + { + case ArgumentBindingDX::Type::DescriptorTable: + d3d12_command_list.SetGraphicsRootDescriptorTable(root_parameter_binding.root_parameter_index, root_parameter_binding.base_descriptor); + break; + + case ArgumentBindingDX::Type::ConstantBufferView: + d3d12_command_list.SetGraphicsRootConstantBufferView(root_parameter_binding.root_parameter_index, root_parameter_binding.gpu_virtual_address); + break; + + case ArgumentBindingDX::Type::ShaderResourceView: + d3d12_command_list.SetComputeRootShaderResourceView(root_parameter_binding.root_parameter_index, root_parameter_binding.gpu_virtual_address); + break; + } +} + +void ProgramBindingsDX::CopyDescriptorsToGpu() +{ + ITT_FUNCTION_TASK(); + + const wrl::ComPtr& cp_device = static_cast(GetProgram()).GetContextDX().GetDeviceDX().GetNativeDevice(); + ForEachArgumentBinding([this, &cp_device](ArgumentBindingDX& argument_binding, const DescriptorHeap::Reservation* p_heap_reservation) + { + if (!p_heap_reservation) + return; + + const DescriptorHeapDX& dx_descriptor_heap = static_cast(p_heap_reservation->heap.get()); + const ArgumentBindingDX::DescriptorRange& descriptor_range = argument_binding.GetDescriptorRange(); + const DescriptorHeap::Type heap_type = dx_descriptor_heap.GetSettings().type; + const bool is_constant_bindinig = argument_binding.GetSettings().argument.IsConstant(); + const uint32_t descriptor_range_start = p_heap_reservation->GetRange(is_constant_bindinig).GetStart(); + const D3D12_DESCRIPTOR_HEAP_TYPE native_heap_type = dx_descriptor_heap.GetNativeDescriptorHeapType(); + + argument_binding.SetDescriptorHeapReservation(p_heap_reservation); + + if (descriptor_range.offset >= p_heap_reservation->GetRange(is_constant_bindinig).GetLength()) + { + throw std::invalid_argument("Descriptor range offset is out of bounds of reserved descriptor range."); + } + + uint32_t resource_index = 0; + for (const ResourceDX::LocationDX& resource_location_dx : argument_binding.GetResourceLocationsDX()) + { + const DescriptorHeap::Types used_heap_types = resource_location_dx.GetResourceDX().GetUsedDescriptorHeapTypes(); + if (used_heap_types.find(heap_type) == used_heap_types.end()) + { + throw std::invalid_argument("Can not create binding for resource used for " + resource_location_dx.GetResourceDX().GetUsageNames() + + " on descriptor heap of incompatible type \"" + dx_descriptor_heap.GetTypeName() + "\"."); + } + + const uint32_t descriptor_index = descriptor_range_start + descriptor_range.offset + resource_index; + + //OutputDebugStringA((dx_resource.GetName() + " range: [" + std::to_string(descriptor_range.offset) + " - " + std::to_string(descriptor_range.offset + descriptor_range.count) + + // "), descriptor: " + std::to_string(descriptor_index) + "\n").c_str()); + + cp_device->CopyDescriptorsSimple(1, + dx_descriptor_heap.GetNativeCpuDescriptorHandle(descriptor_index), + resource_location_dx.GetResourceDX().GetNativeCpuDescriptorHandle(ResourceBase::Usage::ShaderRead), + native_heap_type); + resource_index++; + } + }); +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ProgramBindingsDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ProgramBindingsDX.h new file mode 100644 index 000000000..2efc17840 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ProgramBindingsDX.h @@ -0,0 +1,137 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/DirectX12/ProgramBindingsDX.h +DirectX 12 implementation of the program bindings interface. + +******************************************************************************/ + +#pragma once + +#include "ResourceDX.h" + +#include +//#include + +#include +#include + +#include + +namespace Methane::Graphics +{ + +class ResourceDX; +class RenderCommandListDX; + +namespace wrl = Microsoft::WRL; + +class ProgramBindingsDX final : public ProgramBindingsBase +{ +public: + class ArgumentBindingDX final : public ArgumentBindingBase + { + public: + enum class Type : uint32_t + { + DescriptorTable = 0, + ConstantBufferView, + ShaderResourceView, + }; + + struct SettingsDX : Settings + { + Type type; + D3D_SHADER_INPUT_TYPE input_type; + uint32_t point; + uint32_t space; + }; + + struct DescriptorRange + { + DescriptorHeap::Type heap_type = DescriptorHeap::Type::Undefined; + uint32_t offset = 0; + uint32_t count = 0; + }; + + ArgumentBindingDX(const ContextBase& context, SettingsDX settings); + ArgumentBindingDX(const ArgumentBindingDX& other); + + // ArgumentBinding interface + void SetResourceLocations(const Resource::Locations& resource_locations) override; + + const SettingsDX& GetSettingsDX() const noexcept { return m_settings_dx; } + uint32_t GetRootParameterIndex() const noexcept { return m_root_parameter_index; } + const DescriptorRange& GetDescriptorRange() const noexcept { return m_descriptor_range; } + const ResourceDX::LocationsDX& GetResourceLocationsDX() const noexcept { return m_resource_locations_dx; } + + void SetRootParameterIndex(uint32_t root_parameter_index) { m_root_parameter_index = root_parameter_index; } + void SetDescriptorRange(const DescriptorRange& descriptor_range); + void SetDescriptorHeapReservation(const DescriptorHeap::Reservation* p_reservation) { m_p_descriptor_heap_reservation = p_reservation; } + + private: + const SettingsDX m_settings_dx; + uint32_t m_root_parameter_index = std::numeric_limits::max();; + DescriptorRange m_descriptor_range; + const DescriptorHeap::Reservation* m_p_descriptor_heap_reservation = nullptr; + ResourceDX::LocationsDX m_resource_locations_dx; + }; + + ProgramBindingsDX(const Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument); + ProgramBindingsDX(const ProgramBindingsDX& other_program_bindings, const ResourceLocationsByArgument& replace_resource_locations_by_argument); + + void Initialize(); + + // ProgramBindings interface + void CompleteInitialization() override; + void Apply(CommandListBase& command_list, ApplyBehavior::Mask apply_behavior) const override; + +private: + struct RootParameterBinding + { + ArgumentBindingDX& argument_binding; + uint32_t root_parameter_index = 0u; + D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor = {}; + D3D12_GPU_VIRTUAL_ADDRESS gpu_virtual_address = 0u; + }; + + struct ResourceState + { + Ptr sp_resource; + ResourceBase::State state; + }; + + using ArgumentBindingFunc = std::function; + void ForEachArgumentBinding(const ArgumentBindingFunc& argument_binding_function) const; + void AddRootParameterBinding(const Program::ArgumentDesc& argument_desc, RootParameterBinding root_parameter_binding); + void AddResourceState(const Program::ArgumentDesc& argument_desc, ResourceState resource_state); + void UpdateRootParameterBindings(); + ResourceBase::Barriers ApplyResourceStates(bool apply_constant_resource_states) const; + void ApplyRootParameterBinding(const RootParameterBinding& root_parameter_binding, ID3D12GraphicsCommandList& d3d12_command_list) const; + void CopyDescriptorsToGpu(); + + using RootParameterBindings = std::vector; + RootParameterBindings m_constant_root_parameter_bindings; + RootParameterBindings m_variadic_root_parameter_bindings; + + using ResourceStates = std::vector; + ResourceStates m_constant_resource_states; + ResourceStates m_variadic_resource_states; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ProgramDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ProgramDX.cpp index 05b831313..180799b06 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ProgramDX.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ProgramDX.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,25 +21,20 @@ DirectX 12 implementation of the program interface. ******************************************************************************/ -#include "ContextDX.h" #include "DeviceDX.h" #include "ProgramDX.h" +#include "ProgramBindingsDX.h" #include "ShaderDX.h" -#include "ResourceDX.h" #include "RenderCommandListDX.h" -#include "TypesDX.h" -#include "DescriptorHeapDX.h" -#include +#include +#include #include -#include #include #include #include -#include -#include #include #include @@ -100,227 +95,10 @@ static D3D12_SHADER_VISIBILITY GetShaderVisibilityByType(Shader::Type shader_typ return D3D12_SHADER_VISIBILITY_ALL; }; -Program::ResourceBindings::Ptr Program::ResourceBindings::Create(const Program::Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument) +Ptr Program::Create(Context& context, const Settings& settings) { ITT_FUNCTION_TASK(); - - std::shared_ptr sp_dx_resource_bindings = std::make_shared(sp_program, resource_locations_by_argument); - sp_dx_resource_bindings->Initialize(); // NOTE: Initialize is called externally (not from constructor) to enable using shared_from_this from its code - return sp_dx_resource_bindings; -} - -Program::ResourceBindings::Ptr Program::ResourceBindings::CreateCopy(const ResourceBindings& other_resource_bingings, const ResourceLocationsByArgument& replace_resource_locations_by_argument) -{ - ITT_FUNCTION_TASK(); - - std::shared_ptr sp_dx_resource_bindings = std::make_shared(static_cast(other_resource_bingings), replace_resource_locations_by_argument); - sp_dx_resource_bindings->Initialize(); // NOTE: Initialize is called externally (not from constructor) to enable using shared_from_this from its code - return sp_dx_resource_bindings; -} - -ProgramDX::ResourceBindingsDX::ResourceBindingsDX(const Program::Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument) - : ProgramBase::ResourceBindingsBase(sp_program, resource_locations_by_argument) -{ - ITT_FUNCTION_TASK(); -} - -ProgramDX::ResourceBindingsDX::ResourceBindingsDX(const ResourceBindingsDX& other_resource_bindings, const ResourceLocationsByArgument& replace_resource_locations_by_argument) - : ProgramBase::ResourceBindingsBase(other_resource_bindings, replace_resource_locations_by_argument) -{ - ITT_FUNCTION_TASK(); -} - -void ProgramDX::ResourceBindingsDX::Initialize() -{ - ITT_FUNCTION_TASK(); - - ResourceManager& resource_manager = static_cast(*m_sp_program).GetContext().GetResourceManager(); - if (resource_manager.DeferredHeapAllocationEnabled()) - { - resource_manager.DeferResourceBindingsInitialization(*this); - } - else - { - CompleteInitialization(); - } -} - -void ProgramDX::ResourceBindingsDX::CompleteInitialization() -{ - ITT_FUNCTION_TASK(); - CopyDescriptorsToGpu(); -} - -void ProgramDX::ResourceBindingsDX::Apply(CommandList& command_list, ApplyBehavior::Mask apply_behavior) const -{ - ITT_FUNCTION_TASK(); - - using DXBindingType = ShaderDX::ResourceBindingDX::Type; - using DXDescriptorRange = ShaderDX::ResourceBindingDX::DescriptorRange; - - struct GraphicsRootParameterBinding - { - DXBindingType type = ShaderDX::ResourceBindingDX::Type::DescriptorTable; - uint32_t root_parameter_index = 0; - D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor = {}; - D3D12_GPU_VIRTUAL_ADDRESS gpu_virtual_address = 0u; - }; - - RenderCommandListDX& render_command_list_dx = dynamic_cast(command_list); - wrl::ComPtr& cp_command_list = render_command_list_dx.GetNativeCommandList(); - const CommandListBase::CommandState& command_state = render_command_list_dx.GetCommandState(); - assert(!!cp_command_list); - - ResourceBase::Barriers resource_transition_barriers; - std::vector graphics_root_parameter_bindings; - graphics_root_parameter_bindings.reserve(m_resource_binding_by_argument.size()); - - ForEachResourceBinding([&](const Argument& argument, ShaderDX::ResourceBindingDX& resource_binding, const DescriptorHeap::Reservation* p_heap_reservation) - { - if ((apply_behavior & ApplyBehavior::ConstantOnce || apply_behavior & ApplyBehavior::ChangesOnly) && - resource_binding.IsAlreadyApplied(*m_sp_program, argument, command_state, apply_behavior & ApplyBehavior::ChangesOnly)) - return; - - const DXBindingType binding_type = resource_binding.GetSettings().type; - D3D12_GPU_DESCRIPTOR_HANDLE gpu_descriptor_handle = {}; - - if (binding_type == DXBindingType::DescriptorTable) - { - if (!p_heap_reservation) - throw std::runtime_error("Descriptor heap reservation is not available for \"Descriptor Table\" resource binding."); - - const DescriptorHeapDX& dx_descriptor_heap = static_cast(p_heap_reservation->heap.get()); - const DXDescriptorRange& descriptor_range = resource_binding.GetDescriptorRange(); - const uint32_t descriptor_index = p_heap_reservation->GetRange(resource_binding.IsConstant()).GetStart() + descriptor_range.offset; - gpu_descriptor_handle = dx_descriptor_heap.GetNativeGPUDescriptorHandle(descriptor_index); - graphics_root_parameter_bindings.push_back({ - binding_type, - resource_binding.GetRootParameterIndex(), - gpu_descriptor_handle, - 0 - }); - } - else - { - for (const ResourceDX::LocationDX& resource_location_dx : resource_binding.GetResourceLocationsDX()) - { - graphics_root_parameter_bindings.push_back({ - binding_type, - resource_binding.GetRootParameterIndex(), - gpu_descriptor_handle, - resource_location_dx.GetNativeGpuAddress() - }); - } - } - - if (apply_behavior & ApplyBehavior::StateBarriers) - { - const ResourceBase::State resource_state = resource_binding.GetShaderType() == Shader::Type::Pixel - ? ResourceBase::State::PixelShaderResource - : ResourceBase::State::NonPixelShaderResource; - - for (const ResourceDX::LocationDX& resource_location_dx : resource_binding.GetResourceLocationsDX()) - { - resource_location_dx.GetResourceDX().SetState(resource_state, resource_transition_barriers); - } - } - }); - - // Set resource transition barriers before applying resource bindings - if (!resource_transition_barriers.empty()) - { - render_command_list_dx.SetResourceBarriers(resource_transition_barriers); - } - - // Apply resource bindings - for (const GraphicsRootParameterBinding& binding : graphics_root_parameter_bindings) - { - switch (binding.type) - { - case DXBindingType::DescriptorTable: cp_command_list->SetGraphicsRootDescriptorTable(binding.root_parameter_index, binding.base_descriptor); break; - case DXBindingType::ConstantBufferView: cp_command_list->SetGraphicsRootConstantBufferView(binding.root_parameter_index, binding.gpu_virtual_address); break; - case DXBindingType::ShaderResourceView: cp_command_list->SetComputeRootShaderResourceView(binding.root_parameter_index, binding.gpu_virtual_address); break; - } - } -} - -void ProgramDX::ResourceBindingsDX::ForEachResourceBinding(ApplyResourceBindingFunc apply_resource_binding) const -{ - ITT_FUNCTION_TASK(); - - for (auto& resource_binding_by_argument : m_resource_binding_by_argument) - { - assert(!!resource_binding_by_argument.second); - - ShaderDX::ResourceBindingDX& resource_binding = static_cast(*resource_binding_by_argument.second); - const Argument& program_argument = resource_binding_by_argument.first; - const ShaderDX::ResourceBindingDX::DescriptorRange& descriptor_range = resource_binding.GetDescriptorRange(); - const DescriptorHeap::Reservation* p_heap_reservation = nullptr; - - if (descriptor_range.heap_type != DescriptorHeap::Type::Undefined) - { - const std::optional& descriptor_heap_reservation_opt = m_descriptor_heap_reservations_by_type[static_cast(descriptor_range.heap_type)]; - if (descriptor_heap_reservation_opt) - { - p_heap_reservation = &*descriptor_heap_reservation_opt; - } - } - - apply_resource_binding(program_argument, resource_binding, p_heap_reservation); - } -} - -void ProgramDX::ResourceBindingsDX::CopyDescriptorsToGpu() -{ - ITT_FUNCTION_TASK(); - - assert(!!m_sp_program); - const wrl::ComPtr& cp_device = static_cast(*m_sp_program).GetContextDX().GetDeviceDX().GetNativeDevice(); - ForEachResourceBinding([this, &cp_device](const Argument&, ShaderDX::ResourceBindingDX& resource_binding, const DescriptorHeap::Reservation* p_heap_reservation) - { - if (!p_heap_reservation) - return; - - const DescriptorHeapDX& dx_descriptor_heap = static_cast(p_heap_reservation->heap.get()); - const ShaderDX::ResourceBindingDX::DescriptorRange& descriptor_range = resource_binding.GetDescriptorRange(); - const DescriptorHeap::Type heap_type = dx_descriptor_heap.GetSettings().type; - - resource_binding.SetDescriptorHeapReservation(p_heap_reservation); - - if (descriptor_range.offset >= p_heap_reservation->GetRange(resource_binding.IsConstant()).GetLength()) - { - throw std::invalid_argument("Descriptor range offset is out of bounds of reserved descriptor range."); - } - - uint32_t resource_index = 0; - for (const ResourceDX::LocationDX& resource_location_dx : resource_binding.GetResourceLocationsDX()) - { - const DescriptorHeap::Types used_heap_types = resource_location_dx.GetResourceDX().GetUsedDescriptorHeapTypes(); - if (used_heap_types.find(heap_type) == used_heap_types.end()) - { - throw std::invalid_argument("Can not create binding for resource used for " + resource_location_dx.GetResourceDX().GetUsageNames() + - " on descriptor heap of incompatible type \"" + dx_descriptor_heap.GetTypeName() + "\"."); - } - - const uint32_t descriptor_index = p_heap_reservation->GetRange(resource_binding.IsConstant()).GetStart() - + descriptor_range.offset + resource_index; - - //OutputDebugStringA((dx_resource.GetName() + " range: [" + std::to_string(descriptor_range.offset) + " - " + std::to_string(descriptor_range.offset + descriptor_range.count) + - // "), descriptor: " + std::to_string(descriptor_index) + "\n").c_str()); - - cp_device->CopyDescriptorsSimple(1, - dx_descriptor_heap.GetNativeCPUDescriptorHandle(descriptor_index), - resource_location_dx.GetResourceDX().GetNativeCPUDescriptorHandle(ResourceBase::Usage::ShaderRead), - dx_descriptor_heap.GetNativeDescriptorHeapType()); - resource_index++; - } - }); -} - -Program::Ptr Program::Create(Context& context, const Settings& settings) -{ - ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context), settings); + return std::make_shared(dynamic_cast(context), settings); } ProgramDX::ProgramDX(ContextBase& context, const Settings& settings) @@ -329,7 +107,7 @@ ProgramDX::ProgramDX(ContextBase& context, const Settings& settings) { ITT_FUNCTION_TASK(); - InitResourceBindings(m_settings.constant_argument_names, m_settings.addressable_argument_names); + InitArgumentBindings(settings.argument_descriptions); InitRootSignature(); } @@ -353,51 +131,54 @@ void ProgramDX::InitRootSignature() uint32_t mutable_offset = 0; }; - using ResourceBindingDX = ShaderDX::ResourceBindingDX; + using ArgumentBindingDX = ProgramBindingsDX::ArgumentBindingDX; std::vector descriptor_ranges; std::vector root_parameters; - descriptor_ranges.reserve(m_resource_binding_by_argument.size()); - root_parameters.reserve(m_resource_binding_by_argument.size()); + const ProgramBindings::ArgumentBindings& binding_by_argument = GetArgumentBindings(); + descriptor_ranges.reserve(binding_by_argument.size()); + root_parameters.reserve(binding_by_argument.size()); std::map descriptor_offset_by_heap_type; - for (auto& resource_binding_by_argument : m_resource_binding_by_argument) + for (auto& argument_and_binding : binding_by_argument) { - assert(!!resource_binding_by_argument.second); - const Argument& shader_argument = resource_binding_by_argument.first; - ResourceBindingDX& resource_binding = static_cast(*resource_binding_by_argument.second); - const ResourceBindingDX::Settings& bind_settings = resource_binding.GetSettings(); - const D3D12_SHADER_VISIBILITY shader_visibility = GetShaderVisibilityByType(shader_argument.shader_type); + assert(!!argument_and_binding.second); + const Argument& shader_argument = argument_and_binding.first; + ArgumentBindingDX& argument_binding = static_cast(*argument_and_binding.second); + const ArgumentBindingDX::SettingsDX& bind_settings = argument_binding.GetSettingsDX(); + const D3D12_SHADER_VISIBILITY shader_visibility = GetShaderVisibilityByType(shader_argument.shader_type); - resource_binding.SetRootParameterIndex(static_cast(root_parameters.size())); + argument_binding.SetRootParameterIndex(static_cast(root_parameters.size())); root_parameters.emplace_back(); switch (bind_settings.type) { - case ShaderDX::ResourceBindingDX::Type::DescriptorTable: + case ArgumentBindingDX::Type::DescriptorTable: { const D3D12_DESCRIPTOR_RANGE_TYPE range_type = GetDescriptorRangeTypeByShaderInputType(bind_settings.input_type); const D3D12_DESCRIPTOR_RANGE_FLAGS range_flags = (bind_settings.input_type == D3D_SIT_CBUFFER) ? D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC : D3D12_DESCRIPTOR_RANGE_FLAG_NONE; - descriptor_ranges.emplace_back(range_type, bind_settings.base.resource_count, bind_settings.point, bind_settings.space, range_flags); + descriptor_ranges.emplace_back(range_type, bind_settings.resource_count, bind_settings.point, bind_settings.space, range_flags); root_parameters.back().InitAsDescriptorTable(1, &descriptor_ranges.back(), shader_visibility); const DescriptorHeap::Type heap_type = GetDescriptorHeapTypeByRangeType(range_type); DescriptorOffsets& descriptor_offsets = descriptor_offset_by_heap_type[heap_type]; - uint32_t& descriptor_offset = resource_binding.IsConstant() ? descriptor_offsets.constant_offset : descriptor_offsets.mutable_offset; - resource_binding.SetDescriptorRange({ heap_type, descriptor_offset, bind_settings.base.resource_count }); + uint32_t& descriptor_offset = argument_binding.GetSettings().argument.IsConstant() + ? descriptor_offsets.constant_offset + : descriptor_offsets.mutable_offset; + argument_binding.SetDescriptorRange({ heap_type, descriptor_offset, bind_settings.resource_count }); - descriptor_offset += bind_settings.base.resource_count; + descriptor_offset += bind_settings.resource_count; } break; - case ShaderDX::ResourceBindingDX::Type::ConstantBufferView: + case ArgumentBindingDX::Type::ConstantBufferView: root_parameters.back().InitAsConstantBufferView(bind_settings.point, bind_settings.space, D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC, shader_visibility); break; - case ShaderDX::ResourceBindingDX::Type::ShaderResourceView: + case ArgumentBindingDX::Type::ShaderResourceView: root_parameters.back().InitAsShaderResourceView(bind_settings.point, bind_settings.space, D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC, shader_visibility); break; } @@ -419,16 +200,16 @@ void ProgramDX::InitRootSignature() ThrowIfFailed(GetContextDX().GetDeviceDX().GetNativeDevice()->CreateRootSignature(0, root_signature_blob->GetBufferPointer(), root_signature_blob->GetBufferSize(), IID_PPV_ARGS(&m_cp_root_signature))); } -ContextDX& ProgramDX::GetContextDX() noexcept +IContextDX& ProgramDX::GetContextDX() noexcept { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(GetContext()); } -const ContextDX& ProgramDX::GetContextDX() const noexcept +const IContextDX& ProgramDX::GetContextDX() const noexcept { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(GetContext()); } ShaderDX& ProgramDX::GetVertexShaderDX() noexcept diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ProgramDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ProgramDX.h index c30612245..eea1f36f8 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ProgramDX.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ProgramDX.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -35,7 +35,7 @@ DirectX 12 implementation of the program interface. namespace Methane::Graphics { -class ContextDX; +struct IContextDX; class ResourceDX; namespace wrl = Microsoft::WRL; @@ -43,24 +43,6 @@ namespace wrl = Microsoft::WRL; class ProgramDX final : public ProgramBase { public: - class ResourceBindingsDX : public ResourceBindingsBase - { - public: - ResourceBindingsDX(const Program::Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument); - ResourceBindingsDX(const ResourceBindingsDX& other_resource_bindings, const ResourceLocationsByArgument& replace_resource_locations_by_argument); - - void Initialize(); - - // ResourceBindings interface - void CompleteInitialization() override; - void Apply(CommandList& command_list, ApplyBehavior::Mask apply_behavior) const override; - - protected: - using ApplyResourceBindingFunc = std::function; - void ForEachResourceBinding(ApplyResourceBindingFunc apply_resource_binding) const; - void CopyDescriptorsToGpu(); - }; - ProgramDX(ContextBase& context, const Settings& settings); // Object interface @@ -69,14 +51,14 @@ class ProgramDX final : public ProgramBase ShaderDX& GetVertexShaderDX() noexcept; ShaderDX& GetPixelShaderDX() noexcept; - const wrl::ComPtr& GetNativeRootSignature() const { return m_cp_root_signature; } + const wrl::ComPtr& GetNativeRootSignature() const noexcept { return m_cp_root_signature; } D3D12_INPUT_LAYOUT_DESC GetNativeInputLayoutDesc() const noexcept; -protected: - void InitRootSignature(); + IContextDX& GetContextDX() noexcept; + const IContextDX& GetContextDX() const noexcept; - ContextDX& GetContextDX() noexcept; - const ContextDX& GetContextDX() const noexcept; +private: + void InitRootSignature(); wrl::ComPtr m_cp_root_signature; std::vector m_dx_input_layout; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderCommandListDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderCommandListDX.cpp index 945372444..ade143fbf 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderCommandListDX.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderCommandListDX.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,19 +26,15 @@ DirectX 12 implementation of the render command list interface. #include "RenderStateDX.h" #include "RenderPassDX.h" #include "CommandQueueDX.h" -#include "ContextDX.h" #include "DeviceDX.h" #include "ProgramDX.h" -#include "ResourceDX.h" -#include "TextureDX.h" #include "BufferDX.h" -#include +#include +#include #include #include -#include -#include #include namespace Methane::Graphics @@ -59,68 +55,55 @@ static D3D12_PRIMITIVE_TOPOLOGY PrimitiveToDXTopology(RenderCommandList::Primiti return D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; } -RenderCommandList::Ptr RenderCommandList::Create(CommandQueue& cmd_queue, RenderPass& render_pass) +Ptr RenderCommandList::Create(CommandQueue& cmd_queue, RenderPass& render_pass) { ITT_FUNCTION_TASK(); return std::make_shared(static_cast(cmd_queue), static_cast(render_pass)); } -RenderCommandList::Ptr RenderCommandList::Create(ParallelRenderCommandList& parallel_render_command_list) +Ptr RenderCommandList::Create(ParallelRenderCommandList& parallel_render_command_list) { ITT_FUNCTION_TASK(); return std::make_shared(static_cast(parallel_render_command_list)); } RenderCommandListDX::RenderCommandListDX(CommandQueueBase& cmd_buffer, RenderPassBase& render_pass) - : RenderCommandListBase(cmd_buffer, render_pass) + : CommandListDX(cmd_buffer, render_pass) { ITT_FUNCTION_TASK(); - Initialize(); } RenderCommandListDX::RenderCommandListDX(ParallelRenderCommandListBase& parallel_render_command_list) - : RenderCommandListBase(parallel_render_command_list) + : CommandListDX(parallel_render_command_list) { ITT_FUNCTION_TASK(); - Initialize(); } -void RenderCommandListDX::Initialize() -{ - ITT_FUNCTION_TASK(); - - const wrl::ComPtr& cp_device = GetCommandQueueDX().GetContextDX().GetDeviceDX().GetNativeDevice(); - assert(!!cp_device); - - ThrowIfFailed(cp_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_cp_command_allocator))); - ThrowIfFailed(cp_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_cp_command_allocator.Get(), nullptr, IID_PPV_ARGS(&m_cp_command_list))); - m_cp_command_list.As(&m_cp_command_list_4); -} - -void RenderCommandListDX::ResetNative(const RenderState::Ptr& sp_render_state) +void RenderCommandListDX::ResetNative(const Ptr& sp_render_state) { // Reset command list - if (!m_is_committed) + if (!IsCommitted()) return; - m_is_committed = false; - - ResetDrawState(); + SetCommitted(false); + ResetCommandState(); ID3D12PipelineState* p_dx_initial_state = sp_render_state ? static_cast(*sp_render_state).GetNativePipelineState().Get() : nullptr; - ThrowIfFailed(m_cp_command_allocator->Reset()); - ThrowIfFailed(m_cp_command_list->Reset(m_cp_command_allocator.Get(), p_dx_initial_state)); + ID3D12CommandAllocator& dx_cmd_allocator = GetNativeCommandAllocatorRef(); + ThrowIfFailed(dx_cmd_allocator.Reset()); + ThrowIfFailed(GetNativeCommandListRef().Reset(&dx_cmd_allocator, p_dx_initial_state)); if (!sp_render_state) return; - m_draw_state.sp_render_state = static_cast(*sp_render_state).GetPtr(); - m_draw_state.render_state_groups = RenderState::Group::Program - | RenderState::Group::Rasterizer - | RenderState::Group::DepthStencil; + DrawingState& drawing_state = GetDrawingState(); + drawing_state.p_render_state = static_cast(sp_render_state.get()); + drawing_state.render_state_groups = RenderState::Group::Program + | RenderState::Group::Rasterizer + | RenderState::Group::DepthStencil; } -void RenderCommandListDX::Reset(const RenderState::Ptr& sp_render_state, const std::string& debug_group) +void RenderCommandListDX::Reset(const Ptr& sp_render_state, const std::string& debug_group) { ITT_FUNCTION_TASK(); @@ -129,7 +112,7 @@ void RenderCommandListDX::Reset(const RenderState::Ptr& sp_render_state, const s RenderCommandListBase::Reset(sp_render_state, debug_group); RenderPassDX& pass_dx = GetPassDX(); - if (m_is_parallel) + if (IsParallel()) { pass_dx.SetNativeDescriptorHeaps(*this); pass_dx.SetNativeRenderTargets(*this); @@ -140,38 +123,13 @@ void RenderCommandListDX::Reset(const RenderState::Ptr& sp_render_state, const s } } -void RenderCommandListDX::SetName(const std::string& name) -{ - ITT_FUNCTION_TASK(); - - RenderCommandListBase::SetName(name); - - assert(m_cp_command_list); - m_cp_command_list->SetName(nowide::widen(name).c_str()); - - assert(m_cp_command_allocator); - m_cp_command_allocator->SetName(nowide::widen(name + " allocator").c_str()); -} - -void RenderCommandListDX::PushDebugGroup(const std::string& name) -{ - ITT_FUNCTION_TASK(); - PIXBeginEvent(m_cp_command_list.Get(), 0, nowide::widen(name).c_str()); -} - -void RenderCommandListDX::PopDebugGroup() -{ - ITT_FUNCTION_TASK(); - PIXEndEvent(m_cp_command_list.Get()); -} - -void RenderCommandListDX::SetVertexBuffers(const Buffer::Refs& vertex_buffers) +void RenderCommandListDX::SetVertexBuffers(const Refs& vertex_buffers) { ITT_FUNCTION_TASK(); RenderCommandListBase::SetVertexBuffers(vertex_buffers); - if (!m_draw_state.flags.vertex_buffers_changed) + if (!GetDrawingState().flags.vertex_buffers_changed) return; std::vector vertex_buffer_views; @@ -183,8 +141,7 @@ void RenderCommandListDX::SetVertexBuffers(const Buffer::Refs& vertex_buffers) vertex_buffer_views.push_back(dx_vertex_buffer.GetNativeView()); } - assert(m_cp_command_list); - m_cp_command_list->IASetVertexBuffers(0, static_cast(vertex_buffer_views.size()), vertex_buffer_views.data()); + GetNativeCommandListRef().IASetVertexBuffers(0, static_cast(vertex_buffer_views.size()), vertex_buffer_views.data()); } void RenderCommandListDX::DrawIndexed(Primitive primitive, Buffer& index_buffer, @@ -201,18 +158,18 @@ void RenderCommandListDX::DrawIndexed(Primitive primitive, Buffer& index_buffer, RenderCommandListBase::DrawIndexed(primitive, index_buffer, index_count, start_index, start_vertex, instance_count, start_instance); - assert(m_cp_command_list); - - if (m_draw_state.flags.primitive_type_changed) + ID3D12GraphicsCommandList& dx_command_list = GetNativeCommandListRef(); + DrawingState& drawing_state = GetDrawingState(); + if (drawing_state.flags.primitive_type_changed) { const D3D12_PRIMITIVE_TOPOLOGY primitive_topology = PrimitiveToDXTopology(primitive); - m_cp_command_list->IASetPrimitiveTopology(primitive_topology); + dx_command_list.IASetPrimitiveTopology(primitive_topology); } - if (m_draw_state.flags.index_buffer_changed) + if (drawing_state.flags.index_buffer_changed) { - m_cp_command_list->IASetIndexBuffer(&dx_index_buffer.GetNativeView()); + dx_command_list.IASetIndexBuffer(&dx_index_buffer.GetNativeView()); } - m_cp_command_list->DrawIndexedInstanced(index_count, instance_count, start_index, start_vertex, start_instance); + dx_command_list.DrawIndexedInstanced(index_count, instance_count, start_index, start_vertex, start_instance); } void RenderCommandListDX::Draw(Primitive primitive, uint32_t vertex_count, uint32_t start_vertex, @@ -222,38 +179,20 @@ void RenderCommandListDX::Draw(Primitive primitive, uint32_t vertex_count, uint3 RenderCommandListBase::Draw(primitive, vertex_count, start_vertex, instance_count, start_instance); - assert(m_cp_command_list); - - if (m_draw_state.flags.primitive_type_changed) + ID3D12GraphicsCommandList& dx_command_list = GetNativeCommandListRef(); + if (GetDrawingState().flags.primitive_type_changed) { const D3D12_PRIMITIVE_TOPOLOGY primitive_topology = PrimitiveToDXTopology(primitive); - m_cp_command_list->IASetPrimitiveTopology(primitive_topology); - } - m_cp_command_list->DrawInstanced(vertex_count, instance_count, start_vertex, start_instance); -} - -void RenderCommandListDX::SetResourceBarriers(const ResourceBase::Barriers& resource_barriers) -{ - ITT_FUNCTION_TASK(); - - if (resource_barriers.empty()) - return; - - std::vector dx_resource_barriers; - for (const ResourceBase::Barrier& resource_barrier : resource_barriers) - { - dx_resource_barriers.push_back(ResourceDX::GetNativeResourceBarrier(resource_barrier)); + dx_command_list.IASetPrimitiveTopology(primitive_topology); } - - assert(m_cp_command_list); - m_cp_command_list->ResourceBarrier(static_cast(dx_resource_barriers.size()), dx_resource_barriers.data()); + dx_command_list.DrawInstanced(vertex_count, instance_count, start_vertex, start_instance); } -void RenderCommandListDX::Commit(bool present_drawable) +void RenderCommandListDX::Commit() { ITT_FUNCTION_TASK(); - if (!m_is_parallel) + if (!IsParallel()) { RenderPassDX& pass_dx = GetPassDX(); if (pass_dx.IsBegun()) @@ -262,16 +201,7 @@ void RenderCommandListDX::Commit(bool present_drawable) } } - RenderCommandListBase::Commit(present_drawable); - - m_cp_command_list->Close(); - m_is_committed = true; -} - -CommandQueueDX& RenderCommandListDX::GetCommandQueueDX() -{ - ITT_FUNCTION_TASK(); - return static_cast(GetCommandQueueBase()); + CommandListDX::Commit(); } RenderPassDX& RenderCommandListDX::GetPassDX() @@ -280,14 +210,4 @@ RenderPassDX& RenderCommandListDX::GetPassDX() return static_cast(GetPass()); } -void RenderCommandListDX::Execute(uint32_t frame_index) -{ - ITT_FUNCTION_TASK(); - - RenderCommandListBase::Execute(frame_index); - - // NOTE: In DirectX there's no need for tracking command list completion, so it's completed right away - Complete(frame_index); -} - } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderCommandListDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderCommandListDX.h index d5b9b2729..c49554446 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderCommandListDX.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderCommandListDX.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,66 +23,37 @@ DirectX 12 implementation of the render command list interface. #pragma once -#include "RenderPassDX.h" +#include "CommandListDX.hpp" #include -#include -#include - namespace Methane::Graphics { -namespace wrl = Microsoft::WRL; - -class CommandQueueDX; class RenderPassDX; -class RenderCommandListDX final : public RenderCommandListBase +class RenderCommandListDX final : public CommandListDX { public: RenderCommandListDX(CommandQueueBase& cmd_buffer, RenderPassBase& render_pass); RenderCommandListDX(ParallelRenderCommandListBase& parallel_render_command_list); // CommandList interface - void PushDebugGroup(const std::string& name) override; - void PopDebugGroup() override; - void Commit(bool present_drawable) override; - - // CommandListBase interface - void SetResourceBarriers(const ResourceBase::Barriers& resource_barriers) override; - void Execute(uint32_t frame_index) override; - - void ResetNative(const RenderState::Ptr& sp_render_state = RenderState::Ptr()); + void Commit() override; // RenderCommandList interface - void Reset(const RenderState::Ptr& sp_render_state, const std::string& debug_group) override; - void SetVertexBuffers(const Buffer::Refs& vertex_buffers) override; + void Reset(const Ptr& sp_render_state, const std::string& debug_group) override; + void SetVertexBuffers(const Refs& vertex_buffers) override; void DrawIndexed(Primitive primitive, Buffer& index_buffer, uint32_t index_count, uint32_t start_index, uint32_t start_vertex, uint32_t instance_count, uint32_t start_instance) override; void Draw(Primitive primitive, uint32_t vertex_count, uint32_t start_vertex, uint32_t instance_count, uint32_t start_instance) override; - // Object interface - void SetName(const std::string& name) override; - - const wrl::ComPtr& GetNativeCommandList() const { return m_cp_command_list; } - wrl::ComPtr& GetNativeCommandList() { return m_cp_command_list; } - - const wrl::ComPtr& GetNativeCommandList4() const { return m_cp_command_list_4; } - wrl::ComPtr& GetNativeCommandList4() { return m_cp_command_list_4; } + void ResetNative(const Ptr& sp_render_state = Ptr()); protected: - void Initialize(); - - CommandQueueDX& GetCommandQueueDX(); RenderPassDX& GetPassDX(); - - wrl::ComPtr m_cp_command_allocator; - wrl::ComPtr m_cp_command_list; - wrl::ComPtr m_cp_command_list_4; // extended interface for the same command list (may be unavailable on older Windows) - bool m_is_committed = false; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderContextDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderContextDX.cpp new file mode 100644 index 000000000..e36a3ec81 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderContextDX.cpp @@ -0,0 +1,231 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/DirectX12/RenderContextDX.cpp +DirectX 12 implementation of the render context interface. + +******************************************************************************/ + +#include "RenderContextDX.h" +#include "DeviceDX.h" +#include "CommandQueueDX.h" +#include "TypesDX.h" + +#include +#include + +#ifdef COMMAND_EXECUTION_LOGGING +#include +#endif + +#include +#include +#include + +namespace Methane::Graphics +{ + +static void SetWindowTopMostFlag(HWND window_handle, bool is_top_most) +{ + ITT_FUNCTION_TASK(); + + RECT window_rect = {}; + GetWindowRect(window_handle, &window_rect); + + const HWND window_position = is_top_most ? HWND_TOPMOST : HWND_NOTOPMOST; + SetWindowPos(window_handle, window_position, + window_rect.left, window_rect.top, + window_rect.right - window_rect.left, + window_rect.bottom - window_rect.top, + SWP_FRAMECHANGED | SWP_NOACTIVATE); +} + +static float GetDeviceScaleRatio(DEVICE_SCALE_FACTOR device_scale_factor) +{ + ITT_FUNCTION_TASK(); + + switch (device_scale_factor) + { + case SCALE_100_PERCENT: return 1.0f; + case SCALE_120_PERCENT: return 1.2f; + case SCALE_125_PERCENT: return 1.25f; + case SCALE_140_PERCENT: return 1.4f; + case SCALE_150_PERCENT: return 1.5f; + case SCALE_160_PERCENT: return 1.6f; + case SCALE_175_PERCENT: return 1.75f; + case SCALE_180_PERCENT: return 1.8f; + case SCALE_200_PERCENT: return 2.f; + case SCALE_225_PERCENT: return 2.25f; + case SCALE_250_PERCENT: return 2.5f; + case SCALE_300_PERCENT: return 3.f; + case SCALE_350_PERCENT: return 3.5f; + case SCALE_400_PERCENT: return 4.f; + case SCALE_450_PERCENT: return 4.5f; + case SCALE_500_PERCENT: return 5.f; + default: assert(0); + } + + return 1.f; +} + +Ptr RenderContext::Create(const Platform::AppEnvironment& env, Device& device, const RenderContext::Settings& settings) +{ + ITT_FUNCTION_TASK(); + DeviceBase& device_base = static_cast(device); + Ptr sp_render_context = std::make_shared(env, device_base, settings); + sp_render_context->Initialize(device_base, true); + return sp_render_context; +} + +RenderContextDX::RenderContextDX(const Platform::AppEnvironment& env, DeviceBase& device, const RenderContext::Settings& settings) + : ContextDX(device, settings) + , m_platform_env(env) +{ + ITT_FUNCTION_TASK(); +} + +RenderContextDX::~RenderContextDX() +{ + ITT_FUNCTION_TASK(); +} + +void RenderContextDX::Release() +{ + ITT_FUNCTION_TASK(); + + m_cp_swap_chain.Reset(); + + ContextDX::Release(); +} + +void RenderContextDX::Initialize(DeviceBase& device, bool deferred_heap_allocation) +{ + ITT_FUNCTION_TASK(); + + const Settings& settings = GetSettings(); + + SetDevice(device); + + // DXGI does not allow creating a swapchain targeting a window which has fullscreen styles(no border + topmost) + if (settings.is_full_screen) + { + // Temporary remove top-most flag and restore it when swap-chain is created + SetWindowTopMostFlag(m_platform_env.window_handle, false); + } + + // Initialize swap-chain + + DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {}; + swap_chain_desc.Width = settings.frame_size.width; + swap_chain_desc.Height = settings.frame_size.height; + swap_chain_desc.Format = TypeConverterDX::DataFormatToDXGI(settings.color_format); + swap_chain_desc.BufferCount = settings.frame_buffers_count; + swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + swap_chain_desc.SampleDesc.Count = 1; + + const wrl::ComPtr& cp_dxgi_factory = SystemDX::Get().GetNativeFactory(); + assert(!!cp_dxgi_factory); + + BOOL present_tearing_support = FALSE; + ThrowIfFailed(cp_dxgi_factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &present_tearing_support, sizeof(present_tearing_support))); + if (present_tearing_support) + { + swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + } + + wrl::ComPtr cp_swap_chain; + ID3D12CommandQueue& dx_command_queue = GetRenderCommandQueueDX().GetNativeCommandQueue(); + ThrowIfFailed(cp_dxgi_factory->CreateSwapChainForHwnd(&dx_command_queue, m_platform_env.window_handle, &swap_chain_desc, NULL, NULL, &cp_swap_chain)); + assert(!!cp_swap_chain); + + if (settings.is_full_screen) + { + // Restore top-most flag + SetWindowTopMostFlag(m_platform_env.window_handle, true); + } + + ThrowIfFailed(cp_swap_chain.As(&m_cp_swap_chain)); + + // With tearing support enabled we will handle ALT+Enter key presses in the window message loop rather than let DXGI handle it by calling SetFullscreenState + ThrowIfFailed(cp_dxgi_factory->MakeWindowAssociation(m_platform_env.window_handle, DXGI_MWA_NO_ALT_ENTER)); + + const wrl::ComPtr& cp_device = static_cast(device).GetNativeDevice(); + assert(!!cp_device); + + UpdateFrameBufferIndex(); + + ContextDX::Initialize(device, deferred_heap_allocation); +} + +void RenderContextDX::Resize(const FrameSize& frame_size) +{ + ITT_FUNCTION_TASK(); + + WaitForGpu(WaitFor::RenderComplete); + + ContextDX::Resize(frame_size); + + // Resize the swap chain to the desired dimensions + DXGI_SWAP_CHAIN_DESC1 desc = {}; + m_cp_swap_chain->GetDesc1(&desc); + ThrowIfFailed(m_cp_swap_chain->ResizeBuffers(GetSettings().frame_buffers_count, frame_size.width, frame_size.height, desc.Format, desc.Flags)); + + UpdateFrameBufferIndex(); +} + +void RenderContextDX::Present() +{ + ITT_FUNCTION_TASK(); + SCOPE_TIMER("RenderContextDX::Present"); + + ContextDX::Present(); + + // Preset frame to screen + const uint32_t present_flags = 0; // DXGI_PRESENT_DO_NOT_WAIT + const uint32_t vsync_interval = GetPresentVSyncInterval(); + + assert(m_cp_swap_chain); + ThrowIfFailed(m_cp_swap_chain->Present(vsync_interval, present_flags)); + + OnCpuPresentComplete(); + UpdateFrameBufferIndex(); +} + +float RenderContextDX::GetContentScalingFactor() const +{ + DEVICE_SCALE_FACTOR device_scale_factor = DEVICE_SCALE_FACTOR_INVALID; + HMONITOR monitor_handle = MonitorFromWindow(m_platform_env.window_handle, MONITOR_DEFAULTTONEAREST); + ThrowIfFailed(GetScaleFactorForMonitor(monitor_handle, &device_scale_factor)); + return GetDeviceScaleRatio(device_scale_factor); +} + +CommandQueueDX& RenderContextDX::GetRenderCommandQueueDX() +{ + ITT_FUNCTION_TASK(); + return static_cast(GetRenderCommandQueue()); +} + +uint32_t RenderContextDX::GetNextFrameBufferIndex() +{ + ITT_FUNCTION_TASK(); + assert(!!m_cp_swap_chain); + return m_cp_swap_chain->GetCurrentBackBufferIndex(); +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderContextDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderContextDX.h new file mode 100644 index 000000000..a753992a6 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderContextDX.h @@ -0,0 +1,69 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/DirectX12/RenderContextDX.cpp +DirectX 12 implementation of the render context interface. + +******************************************************************************/ + +#pragma once + +#include "ContextDX.hpp" + +#include + +#include +#include + +namespace Methane::Graphics +{ + +class RenderContextDX final : public ContextDX +{ +public: + RenderContextDX(const Platform::AppEnvironment& env, DeviceBase& device, const RenderContext::Settings& settings); + + ~RenderContextDX() override; + + // RenderContext interface + bool ReadyToRender() const override { return true; } + void Resize(const FrameSize& frame_size) override; + void Present() override; + Platform::AppView GetAppView() const override { return { nullptr }; } + float GetContentScalingFactor() const override; + + // ContextBase interface + void Initialize(DeviceBase& device, bool deferred_heap_allocation) override; + void Release() override; + + CommandQueueDX& GetRenderCommandQueueDX(); + + const wrl::ComPtr& GetNativeSwapChain() const { return m_cp_swap_chain; } + +protected: + inline uint32_t GetPresentVSyncInterval() const { return GetSettings().vsync_enabled ? 1 : 0; } + + // RenderContextBase overrides + uint32_t GetNextFrameBufferIndex() override; + +private: + const Platform::AppEnvironment m_platform_env; + wrl::ComPtr m_cp_swap_chain; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderPassDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderPassDX.cpp index eb5d27746..99ee5fad2 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderPassDX.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderPassDX.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -27,8 +27,8 @@ DirectX 12 implementation of the render pass interface. #include "DeviceDX.h" #include "TypesDX.h" -#include -#include +#include +#include #include #include @@ -39,10 +39,10 @@ DirectX 12 implementation of the render pass interface. namespace Methane::Graphics { -static D3D12_CPU_DESCRIPTOR_HANDLE GetRenderTargetTextureCpuDescriptor(const Texture::WeakPtr& wp_texture) +static D3D12_CPU_DESCRIPTOR_HANDLE GetRenderTargetTextureCpuDescriptor(const WeakPtr& wp_texture) { return !wp_texture.expired() - ? static_cast(*wp_texture.lock()).GetNativeCPUDescriptorHandle(Resource::Usage::RenderTarget) + ? static_cast(*wp_texture.lock()).GetNativeCpuDescriptorHandle(Resource::Usage::RenderTarget) : D3D12_CPU_DESCRIPTOR_HANDLE(); } @@ -81,13 +81,13 @@ RenderPassDX::AccessDesc::AccessDesc(const ColorAttachment& color_attachment) throw std::invalid_argument("Can not clear render target attachment without texture."); } - const Texture::Ptr sp_color_rt = color_attachment.wp_texture.lock(); + const Ptr sp_color_rt = color_attachment.wp_texture.lock(); const DXGI_FORMAT color_format = TypeConverterDX::DataFormatToDXGI(sp_color_rt->GetSettings().pixel_format); const float clear_color_components[4] = { - color_attachment.clear_color.r(), - color_attachment.clear_color.g(), - color_attachment.clear_color.b(), - color_attachment.clear_color.a() + color_attachment.clear_color.GetR(), + color_attachment.clear_color.GetG(), + color_attachment.clear_color.GetB(), + color_attachment.clear_color.GetA() }; beginning.Clear.ClearValue = CD3DX12_CLEAR_VALUE(color_format, clear_color_components); } @@ -148,7 +148,7 @@ D3D12_RENDER_PASS_ENDING_ACCESS_TYPE RenderPassDX::AccessDesc::GetEndingAccessTy RenderPassDX::RTClearInfo::RTClearInfo(const RenderPass::ColorAttachment& color_attach) : cpu_handle(GetRenderTargetTextureCpuDescriptor(color_attach.wp_texture)) - , clear_color{ color_attach.clear_color.r(), color_attach.clear_color.g(), color_attach.clear_color.b(), color_attach.clear_color.a() } + , clear_color{ color_attach.clear_color.GetR(), color_attach.clear_color.GetG(), color_attach.clear_color.GetB(), color_attach.clear_color.GetA() } { ITT_FUNCTION_TASK(); } @@ -183,18 +183,18 @@ static DescriptorHeap::Type GetDescriptorHeapTypeByAccess(RenderPass::Access::Va case RenderPass::Access::Samplers: return DescriptorHeap::Type::Samplers; case RenderPass::Access::RenderTargets: return DescriptorHeap::Type::RenderTargets; case RenderPass::Access::DepthStencil: return DescriptorHeap::Type::DepthStencil; + default: assert(0); } - assert(0); return DescriptorHeap::Type::Undefined; } -RenderPass::Ptr RenderPass::Create(Context& context, const Settings& settings) +Ptr RenderPass::Create(RenderContext& context, const Settings& settings) { ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context), settings); + return std::make_shared(dynamic_cast(context), settings); } -RenderPassDX::RenderPassDX(ContextBase& context, const Settings& settings) +RenderPassDX::RenderPassDX(RenderContextBase& context, const Settings& settings) : RenderPassBase(context, settings) { ITT_FUNCTION_TASK(); @@ -204,7 +204,7 @@ void RenderPassDX::Update(const Settings& settings) { ITT_FUNCTION_TASK(); - const bool settings_changed = m_settings != settings; + const bool settings_changed = GetSettings() != settings; RenderPassBase::Update(settings); if (!m_is_native_render_pass_available.has_value() || m_is_native_render_pass_available.value()) @@ -222,7 +222,8 @@ void RenderPassDX::UpdateNativeRenderPassDesc(bool settings_changed) { ITT_FUNCTION_TASK(); - const bool update_descriptors_only = !settings_changed && m_render_target_descs.size() == m_settings.color_attachments.size(); + const Settings& settings = GetSettings(); + const bool update_descriptors_only = !settings_changed && m_render_target_descs.size() == settings.color_attachments.size(); if (!update_descriptors_only) { m_render_target_descs.clear(); @@ -230,7 +231,7 @@ void RenderPassDX::UpdateNativeRenderPassDesc(bool settings_changed) } uint32_t color_attachment_index = 0; - for (const RenderPassBase::ColorAttachment& color_attachment : m_settings.color_attachments) + for (const RenderPassBase::ColorAttachment& color_attachment : settings.color_attachments) { if (update_descriptors_only) { @@ -246,16 +247,16 @@ void RenderPassDX::UpdateNativeRenderPassDesc(bool settings_changed) } } - if (!m_settings.depth_attachment.wp_texture.expired()) + if (!settings.depth_attachment.wp_texture.expired()) { if (update_descriptors_only && m_depth_stencil_desc) { - m_depth_stencil_desc->cpuDescriptor = GetRenderTargetTextureCpuDescriptor(m_settings.depth_attachment.wp_texture); + m_depth_stencil_desc->cpuDescriptor = GetRenderTargetTextureCpuDescriptor(settings.depth_attachment.wp_texture); } else { - const AccessDesc depth_access(m_settings.depth_attachment, m_settings.stencil_attachment); - const AccessDesc stencil_access(m_settings.stencil_attachment, m_settings.depth_attachment); + const AccessDesc depth_access(settings.depth_attachment, settings.stencil_attachment); + const AccessDesc stencil_access(settings.stencil_attachment, settings.depth_attachment); m_depth_stencil_desc = D3D12_RENDER_PASS_DEPTH_STENCIL_DESC{ depth_access.descriptor, @@ -271,7 +272,8 @@ void RenderPassDX::UpdateNativeClearDesc() ITT_FUNCTION_TASK(); m_rt_clear_infos.clear(); - for (const RenderPassBase::ColorAttachment& color_attach : m_settings.color_attachments) + const Settings& settings = GetSettings(); + for (const RenderPassBase::ColorAttachment& color_attach : settings.color_attachments) { if (color_attach.load_action != RenderPassBase::Attachment::LoadAction::Clear) continue; @@ -283,7 +285,7 @@ void RenderPassDX::UpdateNativeClearDesc() m_rt_clear_infos.emplace_back(color_attach); } - m_ds_clear_info = DSClearInfo(m_settings.depth_attachment, m_settings.stencil_attachment); + m_ds_clear_info = DSClearInfo(settings.depth_attachment, settings.stencil_attachment); } void RenderPassDX::Begin(RenderCommandListBase& command_list) @@ -292,30 +294,30 @@ void RenderPassDX::Begin(RenderCommandListBase& command_list) if (!m_is_updated) { - Update(m_settings); + Update(GetSettings()); m_is_updated = true; } RenderPassBase::Begin(command_list); RenderCommandListDX& command_list_dx = static_cast(command_list); - wrl::ComPtr& cp_dx_command_list = command_list_dx.GetNativeCommandList(); + ID3D12GraphicsCommandList& d3d12_command_list = command_list_dx.GetNativeCommandList(); SetNativeDescriptorHeaps(command_list_dx); // Set RT transition barriers command_list.SetResourceTransitionBarriers(GetColorAttachmentResources(), ResourceBase::State::Present, ResourceBase::State::RenderTarget); - wrl::ComPtr& cp_dx_command_list_4 = command_list_dx.GetNativeCommandList4(); + ID3D12GraphicsCommandList4* p_dx_command_list_4 = command_list_dx.GetNativeCommandList4(); if (!m_is_native_render_pass_available.has_value() || m_is_native_render_pass_available.value()) { - m_is_native_render_pass_available = !!cp_dx_command_list_4; + m_is_native_render_pass_available = !!p_dx_command_list_4; } if (m_is_native_render_pass_available.value()) { // Begin render pass - cp_dx_command_list_4->BeginRenderPass( + p_dx_command_list_4->BeginRenderPass( static_cast(m_render_target_descs.size()), m_render_target_descs.data(), m_depth_stencil_desc ? &*m_depth_stencil_desc : nullptr, m_pass_flags @@ -329,13 +331,13 @@ void RenderPassDX::Begin(RenderCommandListBase& command_list) // Clear render targets for (const RenderPassDX::RTClearInfo& rt_clear : m_rt_clear_infos) { - cp_dx_command_list->ClearRenderTargetView(rt_clear.cpu_handle, rt_clear.clear_color, 0, nullptr); + d3d12_command_list.ClearRenderTargetView(rt_clear.cpu_handle, rt_clear.clear_color, 0, nullptr); } // Clear depth-stencil buffer if (m_ds_clear_info.depth_cleared || m_ds_clear_info.stencil_cleared) { - cp_dx_command_list->ClearDepthStencilView(m_ds_clear_info.cpu_handle, m_ds_clear_info.clear_flags, m_ds_clear_info.depth_value, m_ds_clear_info.stencil_value, 0, nullptr); + d3d12_command_list.ClearDepthStencilView(m_ds_clear_info.cpu_handle, m_ds_clear_info.clear_flags, m_ds_clear_info.depth_value, m_ds_clear_info.stencil_value, 0, nullptr); } } } @@ -346,9 +348,9 @@ void RenderPassDX::End(RenderCommandListBase& command_list) if (m_is_native_render_pass_available.has_value() && m_is_native_render_pass_available.value()) { - wrl::ComPtr& cp_dx_command_list_4 = static_cast(command_list).GetNativeCommandList4(); - assert(!!cp_dx_command_list_4); - cp_dx_command_list_4->EndRenderPass(); + ID3D12GraphicsCommandList4* p_dx_command_list_4 = static_cast(command_list).GetNativeCommandList4(); + assert(!!p_dx_command_list_4); + p_dx_command_list_4->EndRenderPass(); } // Set RT transition barriers @@ -366,47 +368,49 @@ void RenderPassDX::SetNativeRenderPassUsage(bool use_native_render_pass) void RenderPassDX::SetNativeDescriptorHeaps(RenderCommandListDX& dx_command_list) const { - const std::vector descritor_heaps = GetNativeDescriptorHeaps(); - if (descritor_heaps.empty()) + const std::vector descriptor_heaps = GetNativeDescriptorHeaps(); + if (descriptor_heaps.empty()) return; - dx_command_list.GetNativeCommandList()->SetDescriptorHeaps(static_cast(descritor_heaps.size()), descritor_heaps.data()); + dx_command_list.GetNativeCommandList().SetDescriptorHeaps(static_cast(descriptor_heaps.size()), descriptor_heaps.data()); } void RenderPassDX::SetNativeRenderTargets(RenderCommandListDX& dx_command_list) { const std::vector rt_cpu_handles = GetNativeRenderTargetCPUHandles(); const D3D12_CPU_DESCRIPTOR_HANDLE* p_depth_stencil_cpu_handle = GetNativeDepthStencilCPUHandle(); - dx_command_list.GetNativeCommandList()->OMSetRenderTargets(static_cast(rt_cpu_handles.size()), rt_cpu_handles.data(), FALSE, p_depth_stencil_cpu_handle); + dx_command_list.GetNativeCommandList().OMSetRenderTargets(static_cast(rt_cpu_handles.size()), rt_cpu_handles.data(), FALSE, p_depth_stencil_cpu_handle); } std::vector RenderPassDX::GetNativeDescriptorHeaps() const { ITT_FUNCTION_TASK(); - std::vector descritor_heaps; + const Settings& settings = GetSettings(); + const RenderContextBase& context = GetRenderContext(); + std::vector descriptor_heaps; for (Access::Value access : Access::values) { - if (!(m_settings.shader_access_mask & access)) + if (!(settings.shader_access_mask & access)) continue; DescriptorHeap::Type heap_type = GetDescriptorHeapTypeByAccess(access); - DescriptorHeapDX& descriptor_heap_dx = static_cast(m_context.GetResourceManager().GetDefaultShaderVisibleDescriptorHeap(heap_type)); - descritor_heaps.push_back(descriptor_heap_dx.GetNativeDescriptorHeap()); + DescriptorHeapDX& descriptor_heap_dx = static_cast(context.GetResourceManager().GetDefaultShaderVisibleDescriptorHeap(heap_type)); + descriptor_heaps.push_back(descriptor_heap_dx.GetNativeDescriptorHeap()); } - return descritor_heaps; + return descriptor_heaps; } std::vector RenderPassDX::GetNativeRenderTargetCPUHandles() const { ITT_FUNCTION_TASK(); std::vector rt_cpu_handles; - for (const RenderPassBase::ColorAttachment& color_attach : m_settings.color_attachments) + for (const RenderPassBase::ColorAttachment& color_attach : GetSettings().color_attachments) { if (color_attach.wp_texture.expired()) { throw std::invalid_argument("Can not use color attachment without texture."); } - rt_cpu_handles.push_back(static_cast(*color_attach.wp_texture.lock()).GetNativeCPUDescriptorHandle(ResourceBase::Usage::RenderTarget)); + rt_cpu_handles.push_back(static_cast(*color_attach.wp_texture.lock()).GetNativeCpuDescriptorHandle(ResourceBase::Usage::RenderTarget)); } return rt_cpu_handles; } @@ -414,9 +418,11 @@ std::vector RenderPassDX::GetNativeRenderTargetCPUH const D3D12_CPU_DESCRIPTOR_HANDLE* RenderPassDX::GetNativeDepthStencilCPUHandle() { ITT_FUNCTION_TASK(); - if (!m_settings.depth_attachment.wp_texture.expired()) + const Settings& settings = GetSettings(); + if (!settings.depth_attachment.wp_texture.expired()) { - m_depth_stencil_cpu_handle = static_cast(*m_settings.depth_attachment.wp_texture.lock()).GetNativeCPUDescriptorHandle(ResourceBase::Usage::RenderTarget); + m_depth_stencil_cpu_handle = static_cast(*settings.depth_attachment.wp_texture.lock()).GetNativeCpuDescriptorHandle( + ResourceBase::Usage::RenderTarget); return &m_depth_stencil_cpu_handle; } return nullptr; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderPassDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderPassDX.h index f3bcf0d9e..3120fbf74 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderPassDX.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderPassDX.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -35,10 +35,10 @@ namespace Methane::Graphics class RenderCommandListDX; -class RenderPassDX : public RenderPassBase +class RenderPassDX final : public RenderPassBase { public: - RenderPassDX(ContextBase& context, const Settings& settings); + RenderPassDX(RenderContextBase& context, const Settings& settings); // RenderPass interface void Update(const Settings& settings) override; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderStateDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderStateDX.cpp index 3792b2334..df924789c 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderStateDX.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderStateDX.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ DirectX 12 implementation of the render state interface. ******************************************************************************/ #include "RenderStateDX.h" -#include "ContextDX.h" +#include "RenderContextDX.h" #include "DeviceDX.h" #include "ProgramDX.h" #include "ShaderDX.h" @@ -32,7 +32,7 @@ DirectX 12 implementation of the render state interface. #include #include -#include +#include #include #include @@ -44,11 +44,12 @@ namespace Methane::Graphics constexpr size_t g_max_rtv_count = sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC::RTVFormats) / sizeof(DXGI_FORMAT); -inline CD3DX12_SHADER_BYTECODE GetShaderByteCode(const Shader::Ptr& sp_shader) +inline CD3DX12_SHADER_BYTECODE GetShaderByteCode(const Ptr& sp_shader) { ITT_FUNCTION_TASK(); - return sp_shader - ? CD3DX12_SHADER_BYTECODE(static_cast(*sp_shader).GetNativeByteCode().Get()) + const Data::Chunk* p_byte_code_chunk = sp_shader ? static_cast(*sp_shader).GetNativeByteCode() : nullptr; + return p_byte_code_chunk + ? CD3DX12_SHADER_BYTECODE(p_byte_code_chunk->p_data, p_byte_code_chunk->size) : CD3DX12_SHADER_BYTECODE(NULL, 0); } @@ -187,13 +188,13 @@ static D3D12_DEPTH_STENCILOP_DESC ConvertStencilFaceOperationsToD3D12(const Rend return stencil_desc; } -RenderState::Ptr RenderState::Create(Context& context, const RenderState::Settings& state_settings) +Ptr RenderState::Create(RenderContext& context, const RenderState::Settings& state_settings) { ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context), state_settings); + return std::make_shared(dynamic_cast(context), state_settings); } -RenderStateDX::RenderStateDX(ContextBase& context, const Settings& settings) +RenderStateDX::RenderStateDX(RenderContextBase& context, const Settings& settings) : RenderStateBase(context, settings) { ITT_FUNCTION_TASK(); @@ -209,20 +210,20 @@ void RenderStateDX::Reset(const Settings& settings) Program::Settings program_settings = dx_program.GetSettings(); // Set Rasterizer state descriptor - CD3DX12_RASTERIZER_DESC rasterizer_desc(D3D12_DEFAULT); - rasterizer_desc.FillMode = ConvertRasterizerFillModeToD3D12(m_settings.rasterizer.fill_mode); - rasterizer_desc.CullMode = ConvertRasterizerCullModeToD3D12(m_settings.rasterizer.cull_mode); - rasterizer_desc.FrontCounterClockwise = m_settings.rasterizer.is_front_counter_clockwise; - rasterizer_desc.MultisampleEnable = m_settings.rasterizer.sample_count > 1; - rasterizer_desc.ForcedSampleCount = !m_settings.depth.enabled && !m_settings.stencil.enabled ? m_settings.rasterizer.sample_count : 0; + CD3DX12_RASTERIZER_DESC rasterizer_desc(D3D12_DEFAULT); + rasterizer_desc.FillMode = ConvertRasterizerFillModeToD3D12(settings.rasterizer.fill_mode); + rasterizer_desc.CullMode = ConvertRasterizerCullModeToD3D12(settings.rasterizer.cull_mode); + rasterizer_desc.FrontCounterClockwise = settings.rasterizer.is_front_counter_clockwise; + rasterizer_desc.MultisampleEnable = settings.rasterizer.sample_count > 1; + rasterizer_desc.ForcedSampleCount = !settings.depth.enabled && !settings.stencil.enabled ? settings.rasterizer.sample_count : 0; // Set Blending state descriptor CD3DX12_BLEND_DESC blend_desc(D3D12_DEFAULT); - blend_desc.AlphaToCoverageEnable = m_settings.rasterizer.alpha_to_coverage_enabled; - blend_desc.IndependentBlendEnable = m_settings.blending.is_independent; + blend_desc.AlphaToCoverageEnable = settings.rasterizer.alpha_to_coverage_enabled; + blend_desc.IndependentBlendEnable = settings.blending.is_independent; uint32_t rt_index = 0; - for (const Blending::RenderTarget& render_target : m_settings.blending.render_targets) + for (const Blending::RenderTarget& render_target : settings.blending.render_targets) { // Set render target blending descriptor D3D12_RENDER_TARGET_BLEND_DESC& rt_blend_desc = blend_desc.RenderTarget[rt_index++]; @@ -237,22 +238,22 @@ void RenderStateDX::Reset(const Settings& settings) } // Set blending factor - assert(m_settings.blending_color.size() <= 4); - for (uint32_t component_index = 0; component_index < static_cast(m_settings.blending_color.size()); ++component_index) + assert(settings.blending_color.size() <= 4); + for (uint32_t component_index = 0; component_index < static_cast(settings.blending_color.size()); ++component_index) { - m_blend_factor[component_index] = m_settings.blending_color[component_index]; + m_blend_factor[component_index] = settings.blending_color[component_index]; } // Set depth and stencil state descriptor CD3DX12_DEPTH_STENCIL_DESC depth_stencil_desc(D3D12_DEFAULT); - depth_stencil_desc.DepthEnable = m_settings.depth.enabled; - depth_stencil_desc.DepthWriteMask = m_settings.depth.write_enabled ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; - depth_stencil_desc.DepthFunc = TypeConverterDX::CompareFunctionToDX(m_settings.depth.compare); - depth_stencil_desc.StencilEnable = m_settings.stencil.enabled; - depth_stencil_desc.StencilReadMask = m_settings.stencil.read_mask; - depth_stencil_desc.StencilWriteMask = m_settings.stencil.write_mask; - depth_stencil_desc.FrontFace = ConvertStencilFaceOperationsToD3D12(m_settings.stencil.front_face); - depth_stencil_desc.BackFace = ConvertStencilFaceOperationsToD3D12(m_settings.stencil.back_face); + depth_stencil_desc.DepthEnable = settings.depth.enabled; + depth_stencil_desc.DepthWriteMask = settings.depth.write_enabled ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; + depth_stencil_desc.DepthFunc = TypeConverterDX::CompareFunctionToDX(settings.depth.compare); + depth_stencil_desc.StencilEnable = settings.stencil.enabled; + depth_stencil_desc.StencilReadMask = settings.stencil.read_mask; + depth_stencil_desc.StencilWriteMask = settings.stencil.write_mask; + depth_stencil_desc.FrontFace = ConvertStencilFaceOperationsToD3D12(settings.stencil.front_face); + depth_stencil_desc.BackFace = ConvertStencilFaceOperationsToD3D12(settings.stencil.back_face); // Set pipeline state descriptor for program m_pipeline_state_desc.InputLayout = dx_program.GetNativeInputLayoutDesc(); @@ -264,13 +265,13 @@ void RenderStateDX::Reset(const Settings& settings) m_pipeline_state_desc.RasterizerState = rasterizer_desc; m_pipeline_state_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; // Not used: for GS or HS shaders only m_pipeline_state_desc.SampleMask = UINT_MAX; - m_pipeline_state_desc.SampleDesc.Count = m_settings.rasterizer.sample_count; + m_pipeline_state_desc.SampleDesc.Count = settings.rasterizer.sample_count; // Set RTV, DSV formats for pipeline state if (program_settings.color_formats.size() > g_max_rtv_count) { - throw new std::runtime_error("Number of color attachments (" + std::to_string(program_settings.color_formats.size()) + - ") exceeds maximum RTV count in DirectX (" + std::to_string(g_max_rtv_count) + ")"); + throw std::runtime_error("Number of color attachments (" + std::to_string(program_settings.color_formats.size()) + + ") exceeds maximum RTV count in DirectX (" + std::to_string(g_max_rtv_count) + ")"); } std::fill_n(m_pipeline_state_desc.RTVFormats, g_max_rtv_count, DXGI_FORMAT_UNKNOWN); uint32_t attachment_index = 0; @@ -279,10 +280,10 @@ void RenderStateDX::Reset(const Settings& settings) m_pipeline_state_desc.RTVFormats[attachment_index++] = TypeConverterDX::DataFormatToDXGI(color_format); } m_pipeline_state_desc.NumRenderTargets = static_cast(program_settings.color_formats.size()); - m_pipeline_state_desc.DSVFormat = m_settings.depth.enabled ? TypeConverterDX::DataFormatToDXGI(program_settings.depth_format) : DXGI_FORMAT_UNKNOWN; + m_pipeline_state_desc.DSVFormat = settings.depth.enabled ? TypeConverterDX::DataFormatToDXGI(program_settings.depth_format) : DXGI_FORMAT_UNKNOWN; - m_viewports = TypeConverterDX::ViewportsToD3D(m_settings.viewports); - m_scissor_rects = TypeConverterDX::ScissorRectsToD3D(m_settings.scissor_rects); + m_viewports = TypeConverterDX::ViewportsToD3D(settings.viewports); + m_scissor_rects = TypeConverterDX::ScissorRectsToD3D(settings.scissor_rects); m_cp_pipeline_state.Reset(); } @@ -291,30 +292,30 @@ void RenderStateDX::Apply(RenderCommandListBase& command_list, Group::Mask state { ITT_FUNCTION_TASK(); - RenderCommandListDX& dx_command_list = static_cast(command_list); - wrl::ComPtr& cp_dx_command_list = dx_command_list.GetNativeCommandList(); + RenderCommandListDX& dx_render_command_list = static_cast(command_list); + ID3D12GraphicsCommandList& d3d12_command_list = dx_render_command_list.GetNativeCommandList(); if (state_groups & Group::Program || state_groups & Group::Rasterizer || state_groups & Group::Blending || state_groups & Group::DepthStencil) { - cp_dx_command_list->SetPipelineState(GetNativePipelineState().Get()); + d3d12_command_list.SetPipelineState(GetNativePipelineState().Get()); } - cp_dx_command_list->SetGraphicsRootSignature(GetProgramDX().GetNativeRootSignature().Get()); + d3d12_command_list.SetGraphicsRootSignature(GetProgramDX().GetNativeRootSignature().Get()); if (state_groups & Group::Viewports) { - cp_dx_command_list->RSSetViewports(static_cast(m_viewports.size()), m_viewports.data()); + d3d12_command_list.RSSetViewports(static_cast(m_viewports.size()), m_viewports.data()); } if (state_groups & Group::ScissorRects) { - cp_dx_command_list->RSSetScissorRects(static_cast(m_scissor_rects.size()), m_scissor_rects.data()); + d3d12_command_list.RSSetScissorRects(static_cast(m_scissor_rects.size()), m_scissor_rects.data()); } if (state_groups & Group::BlendingColor) { - cp_dx_command_list->OMSetBlendFactor(m_blend_factor); + d3d12_command_list.OMSetBlendFactor(m_blend_factor); } } @@ -346,13 +347,22 @@ void RenderStateDX::SetName(const std::string& name) } } +void RenderStateDX::InitializeNativePipelineState() +{ + ITT_FUNCTION_TASK(); + if (m_cp_pipeline_state) + return; + + ThrowIfFailed(GetRenderContextDX().GetDeviceDX().GetNativeDevice()->CreateGraphicsPipelineState(&m_pipeline_state_desc, IID_PPV_ARGS(&m_cp_pipeline_state))); + SetName(GetName()); +} + wrl::ComPtr& RenderStateDX::GetNativePipelineState() { ITT_FUNCTION_TASK(); if (!m_cp_pipeline_state) { - ThrowIfFailed(GetContextDX().GetDeviceDX().GetNativeDevice()->CreateGraphicsPipelineState(&m_pipeline_state_desc, IID_PPV_ARGS(&m_cp_pipeline_state))); - SetName(GetName()); + InitializeNativePipelineState(); } return m_cp_pipeline_state; } @@ -360,14 +370,13 @@ wrl::ComPtr& RenderStateDX::GetNativePipelineState() ProgramDX& RenderStateDX::GetProgramDX() { ITT_FUNCTION_TASK(); - assert(!!m_settings.sp_program); - return static_cast(*m_settings.sp_program); + return static_cast(GetProgram()); } -ContextDX& RenderStateDX::GetContextDX() +RenderContextDX& RenderStateDX::GetRenderContextDX() { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(GetRenderContext()); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderStateDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderStateDX.h index 587f19324..9f0d16699 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderStateDX.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/RenderStateDX.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -34,15 +34,14 @@ namespace Methane::Graphics namespace wrl = Microsoft::WRL; -class ContextBase; class RenderCommandListBase; -class ContextDX; +class RenderContextDX; class ProgramDX; class RenderStateDX final : public RenderStateBase { public: - RenderStateDX(ContextBase& context, const Settings& settings); + RenderStateDX(RenderContextBase& context, const Settings& settings); // RenderState interface void Reset(const Settings& settings) override; @@ -55,11 +54,12 @@ class RenderStateDX final : public RenderStateBase // Object interface void SetName(const std::string& name) override; + void InitializeNativePipelineState(); wrl::ComPtr& GetNativePipelineState(); -protected: +private: ProgramDX& GetProgramDX(); - ContextDX& GetContextDX(); + RenderContextDX& GetRenderContextDX(); D3D12_GRAPHICS_PIPELINE_STATE_DESC m_pipeline_state_desc = { }; wrl::ComPtr m_cp_pipeline_state; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ResourceDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ResourceDX.cpp index ee94aafd9..111555302 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ResourceDX.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ResourceDX.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,10 +23,10 @@ DirectX 12 implementation of the resource interface. #include "ResourceDX.h" #include "DescriptorHeapDX.h" -#include "ContextDX.h" +#include "RenderContextDX.h" #include "DeviceDX.h" -#include +#include #include #include @@ -35,7 +35,7 @@ DirectX 12 implementation of the resource interface. namespace Methane::Graphics { -ResourceBase::ReleasePool::Ptr ResourceBase::ReleasePool::Create() +Ptr ResourceBase::ReleasePool::Create() { ITT_FUNCTION_TASK(); return std::make_shared(); @@ -45,7 +45,10 @@ void ResourceDX::ReleasePoolDX::AddResource(ResourceBase& resource) { ITT_FUNCTION_TASK(); ResourceDX& resource_dx = static_cast(resource); - m_resources.push_back(resource_dx.GetNativeResource()); + const wrl::ComPtr& cp_native_resource = resource_dx.GetNativeResourceComPtr(); + assert(!!cp_native_resource || resource_dx.GetResourceType() == Resource::Type::Sampler); + if (cp_native_resource) + m_resources.emplace_back(cp_native_resource); } void ResourceDX::ReleasePoolDX::ReleaseResources() @@ -84,7 +87,7 @@ ResourceDX::ResourceDX(Type type, Usage::Mask usage_mask, ContextBase& context, ResourceDX::~ResourceDX() { ITT_FUNCTION_TASK(); - m_context.GetResourceManager().GetReleasePool().AddResource(*this); + GetContext().GetResourceManager().GetReleasePool().AddResource(*this); } void ResourceDX::SetName(const std::string& name) @@ -99,16 +102,23 @@ void ResourceDX::SetName(const std::string& name) } } -D3D12_CPU_DESCRIPTOR_HANDLE ResourceDX::GetNativeCPUDescriptorHandle(const Descriptor& desc) const noexcept +ID3D12Resource& ResourceDX::GetNativeResourceRef() const { ITT_FUNCTION_TASK(); - return static_cast(desc.heap).GetNativeCPUDescriptorHandle(desc.index); + assert(!!m_cp_resource); + return *m_cp_resource.Get(); } -D3D12_GPU_DESCRIPTOR_HANDLE ResourceDX::GetNativeGPUDescriptorHandle(const Descriptor& desc) const noexcept +D3D12_CPU_DESCRIPTOR_HANDLE ResourceDX::GetNativeCpuDescriptorHandle(const Descriptor& desc) const noexcept { ITT_FUNCTION_TASK(); - return static_cast(desc.heap).GetNativeGPUDescriptorHandle(desc.index); + return static_cast(desc.heap).GetNativeCpuDescriptorHandle(desc.index); +} + +D3D12_GPU_DESCRIPTOR_HANDLE ResourceDX::GetNativeGpuDescriptorHandle(const Descriptor& desc) const noexcept +{ + ITT_FUNCTION_TASK(); + return static_cast(desc.heap).GetNativeGpuDescriptorHandle(desc.index); } D3D12_RESOURCE_STATES ResourceDX::GetNativeResourceState(State resource_state) noexcept @@ -156,10 +166,10 @@ D3D12_RESOURCE_BARRIER ResourceDX::GetNativeResourceBarrier(const Barrier& resou return D3D12_RESOURCE_BARRIER(); } -ContextDX& ResourceDX::GetContextDX() noexcept +IContextDX& ResourceDX::GetContextDX() noexcept { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(GetContext()); } void ResourceDX::InitializeCommittedResource(const D3D12_RESOURCE_DESC& resource_desc, D3D12_HEAP_TYPE heap_type, @@ -168,9 +178,10 @@ void ResourceDX::InitializeCommittedResource(const D3D12_RESOURCE_DESC& resource ITT_FUNCTION_TASK(); assert(!m_cp_resource); + const CD3DX12_HEAP_PROPERTIES heap_properties(heap_type); ThrowIfFailed( GetContextDX().GetDeviceDX().GetNativeDevice()->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(heap_type), + &heap_properties, D3D12_HEAP_FLAG_NONE, &resource_desc, resource_state, @@ -186,7 +197,7 @@ void ResourceDX::InitializeFrameBufferResource(uint32_t frame_buffer_index) assert(!m_cp_resource); ThrowIfFailed( - GetContextDX().GetNativeSwapChain()->GetBuffer( + static_cast(GetContextDX()).GetNativeSwapChain()->GetBuffer( frame_buffer_index, IID_PPV_ARGS(&m_cp_resource) ) diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ResourceDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ResourceDX.h index 76406589f..c0e17c6b7 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ResourceDX.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ResourceDX.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -34,13 +34,13 @@ namespace Methane::Graphics namespace wrl = Microsoft::WRL; -class ContextDX; +struct IContextDX; class DescriptorHeapDX; class ResourceDX : public ResourceBase { public: - class ReleasePoolDX : public ResourceBase::ReleasePool + class ReleasePoolDX final : public ReleasePool { public: ReleasePoolDX() = default; @@ -64,7 +64,7 @@ class ResourceDX : public ResourceBase D3D12_GPU_VIRTUAL_ADDRESS GetNativeGpuAddress() const noexcept { return GetResourceDX().GetNativeGpuAddress() + GetOffset(); } private: - std::reference_wrapper m_resource_dx; + Ref m_resource_dx; }; using LocationsDX = std::vector; @@ -75,23 +75,26 @@ class ResourceDX : public ResourceBase // Object interface void SetName(const std::string& name) override; - ID3D12Resource* GetNativeResource() const noexcept { return m_cp_resource.Get(); } - D3D12_GPU_VIRTUAL_ADDRESS GetNativeGpuAddress() const noexcept { return m_cp_resource ? m_cp_resource->GetGPUVirtualAddress() : 0; } - D3D12_CPU_DESCRIPTOR_HANDLE GetNativeCPUDescriptorHandle(Usage::Value usage) const noexcept { return GetNativeCPUDescriptorHandle(GetDescriptorByUsage(usage)); } - D3D12_CPU_DESCRIPTOR_HANDLE GetNativeCPUDescriptorHandle(const Descriptor& desc) const noexcept; - D3D12_GPU_DESCRIPTOR_HANDLE GetNativeGPUDescriptorHandle(Usage::Value usage) const noexcept { return GetNativeGPUDescriptorHandle(GetDescriptorByUsage(usage)); } - D3D12_GPU_DESCRIPTOR_HANDLE GetNativeGPUDescriptorHandle(const Descriptor& desc) const noexcept; + ID3D12Resource& GetNativeResourceRef() const; + ID3D12Resource* GetNativeResource() const noexcept { return m_cp_resource.Get(); } + const wrl::ComPtr& GetNativeResourceComPtr() const noexcept { return m_cp_resource; } + D3D12_GPU_VIRTUAL_ADDRESS GetNativeGpuAddress() const noexcept { return m_cp_resource ? m_cp_resource->GetGPUVirtualAddress() : 0; } + D3D12_CPU_DESCRIPTOR_HANDLE GetNativeCpuDescriptorHandle(Usage::Value usage) const noexcept { return GetNativeCpuDescriptorHandle(GetDescriptorByUsage(usage)); } + D3D12_CPU_DESCRIPTOR_HANDLE GetNativeCpuDescriptorHandle(const Descriptor& desc) const noexcept; + D3D12_GPU_DESCRIPTOR_HANDLE GetNativeGpuDescriptorHandle(Usage::Value usage) const noexcept { return GetNativeGpuDescriptorHandle(GetDescriptorByUsage(usage)); } + D3D12_GPU_DESCRIPTOR_HANDLE GetNativeGpuDescriptorHandle(const Descriptor& desc) const noexcept; - static D3D12_RESOURCE_STATES GetNativeResourceState(State resource_state) noexcept; - static D3D12_RESOURCE_BARRIER GetNativeResourceBarrier(const Barrier& resource_barrier) noexcept; + static D3D12_RESOURCE_STATES GetNativeResourceState(State resource_state) noexcept; + static D3D12_RESOURCE_BARRIER GetNativeResourceBarrier(const Barrier& resource_barrier) noexcept; protected: - ContextDX& GetContextDX() noexcept; + IContextDX& GetContextDX() noexcept; void InitializeCommittedResource(const D3D12_RESOURCE_DESC& resource_desc, D3D12_HEAP_TYPE heap_type, D3D12_RESOURCE_STATES resource_state, const D3D12_CLEAR_VALUE* p_clear_value = nullptr); void InitializeFrameBufferResource(uint32_t frame_buffer_index); +private: wrl::ComPtr m_cp_resource; }; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/SamplerDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/SamplerDX.cpp index 1ccfdaa76..70513324e 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/SamplerDX.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/SamplerDX.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,11 +22,11 @@ DirectX 12 implementation of the sampler interface. ******************************************************************************/ #include "SamplerDX.h" -#include "ContextDX.h" #include "DeviceDX.h" #include "TypesDX.h" -#include +#include +#include #include @@ -171,10 +171,10 @@ static void ConvertBorderColorToDXColor(SamplerBase::BorderColor border_color, F } } -Sampler::Ptr Sampler::Create(Context& context, const Sampler::Settings& settings, const DescriptorByUsage& descriptor_by_usage) +Ptr Sampler::Create(Context& context, const Sampler::Settings& settings, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context), settings, descriptor_by_usage); + return std::make_shared(dynamic_cast(context), settings, descriptor_by_usage); } SamplerDX::SamplerDX(ContextBase& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage) @@ -185,18 +185,18 @@ SamplerDX::SamplerDX(ContextBase& context, const Settings& settings, const Descr InitializeDefaultDescriptors(); D3D12_SAMPLER_DESC dx_sampler_desc = {}; - dx_sampler_desc.Filter = ConvertFilterToDX(m_settings.filter); - dx_sampler_desc.AddressU = ConvertAddressModeToDX(m_settings.address.r); - dx_sampler_desc.AddressV = ConvertAddressModeToDX(m_settings.address.s); - dx_sampler_desc.AddressW = ConvertAddressModeToDX(m_settings.address.t); - dx_sampler_desc.MinLOD = m_settings.lod.min; - dx_sampler_desc.MaxLOD = m_settings.lod.max; - dx_sampler_desc.MipLODBias = m_settings.lod.bias; + dx_sampler_desc.Filter = ConvertFilterToDX(settings.filter); + dx_sampler_desc.AddressU = ConvertAddressModeToDX(settings.address.r); + dx_sampler_desc.AddressV = ConvertAddressModeToDX(settings.address.s); + dx_sampler_desc.AddressW = ConvertAddressModeToDX(settings.address.t); + dx_sampler_desc.MinLOD = settings.lod.min; + dx_sampler_desc.MaxLOD = settings.lod.max; + dx_sampler_desc.MipLODBias = settings.lod.bias; dx_sampler_desc.MaxAnisotropy = 0; - dx_sampler_desc.ComparisonFunc = TypeConverterDX::CompareFunctionToDX(m_settings.compare_function); - ConvertBorderColorToDXColor(m_settings.border_color, &dx_sampler_desc.BorderColor[0]); + dx_sampler_desc.ComparisonFunc = TypeConverterDX::CompareFunctionToDX(settings.compare_function); + ConvertBorderColorToDXColor(settings.border_color, &dx_sampler_desc.BorderColor[0]); - GetContextDX().GetDeviceDX().GetNativeDevice()->CreateSampler(&dx_sampler_desc, GetNativeCPUDescriptorHandle(Usage::ShaderRead)); + GetContextDX().GetDeviceDX().GetNativeDevice()->CreateSampler(&dx_sampler_desc, GetNativeCpuDescriptorHandle(Usage::ShaderRead)); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/SamplerDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/SamplerDX.h index 77b88b39c..46c28a200 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/SamplerDX.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/SamplerDX.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -40,7 +40,6 @@ class SamplerDX final : public SamplerBase public: SamplerDX(ContextBase& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); -protected: // NOTE: SamplerBase descriptor is stored in heap }; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ShaderDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ShaderDX.cpp index ecc3af3f9..028a30260 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ShaderDX.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ShaderDX.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,19 +23,18 @@ DirectX 12 implementation of the shader interface. #include "ShaderDX.h" #include "ProgramDX.h" -#include "ResourceDX.h" -#include "ContextDX.h" +#include "ProgramBindingsDX.h" #include "DeviceDX.h" #include "TypesDX.h" -#include -#include -#include - -#include +#include +#include #include #include +#include +#include +#include #include #include @@ -184,104 +183,10 @@ static D3D12_INPUT_CLASSIFICATION GetInputClassificationByLayoutStepType(StepTyp return D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; } -Shader::ResourceBinding::Ptr Shader::ResourceBinding::CreateCopy(const ResourceBinding& other_resource_binging) -{ - ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(other_resource_binging)); -} - -ShaderDX::ResourceBindingDX::ResourceBindingDX(ContextBase& context, const Settings& settings) - : ShaderBase::ResourceBindingBase(context, settings.base) - , m_settings_dx(settings) -{ - ITT_FUNCTION_TASK(); -} - -ShaderDX::ResourceBindingDX::ResourceBindingDX(const ResourceBindingDX& other) - : ResourceBindingBase(other) - , m_settings_dx(other.m_settings_dx) - , m_root_parameter_index(other.m_root_parameter_index) - , m_descriptor_range(other.m_descriptor_range) - , m_p_descriptor_heap_reservation(other.m_p_descriptor_heap_reservation) - , m_resource_locations_dx(other.m_resource_locations_dx) -{ - ITT_FUNCTION_TASK(); -} - -void ShaderDX::ResourceBindingDX::SetResourceLocations(const Resource::Locations& resource_locations) -{ - ITT_FUNCTION_TASK(); - - ShaderBase::ResourceBindingBase::SetResourceLocations(resource_locations); - - m_resource_locations_dx.clear(); - - if (m_settings_dx.type == Type::DescriptorTable && - m_resource_locations.size() > m_descriptor_range.count) - { - throw std::invalid_argument("The number of bound resources (" + std::to_string(m_resource_locations.size()) + - ") exceeds reserved descriptors count (" + std::to_string(m_descriptor_range.count) + ")."); - } - - uint32_t resource_index = 0; - m_resource_locations_dx.reserve(m_resource_locations.size()); - for(const Resource::Location& resource_location : m_resource_locations) - { - m_resource_locations_dx.emplace_back(resource_location); - - if (!m_p_descriptor_heap_reservation) - continue; - - const ResourceDX::LocationDX& resource_location_dx = m_resource_locations_dx.back(); - const DescriptorHeapDX& dx_descriptor_heap = static_cast(m_p_descriptor_heap_reservation->heap.get()); - if (m_descriptor_range.heap_type != dx_descriptor_heap.GetSettings().type) - { - throw std::logic_error("Incompatible heap type \"" + dx_descriptor_heap.GetTypeName() + - "\" is set for resource binding on argument \"" + GetArgumentName() + - "\" of \"" + Shader::GetTypeName(m_settings.shader_type) + "\" shader."); - } - - const uint32_t descriptor_index = m_p_descriptor_heap_reservation->GetRange(IsConstant()).GetStart() + m_descriptor_range.offset + resource_index; - GetContextDX().GetDeviceDX().GetNativeDevice()->CopyDescriptorsSimple( - 1, - dx_descriptor_heap.GetNativeCPUDescriptorHandle(descriptor_index), - resource_location_dx.GetResourceDX().GetNativeCPUDescriptorHandle(ResourceBase::Usage::ShaderRead), - dx_descriptor_heap.GetNativeDescriptorHeapType() - ); - - resource_index++; - } -} - -void ShaderDX::ResourceBindingDX::SetDescriptorRange(const DescriptorRange& descriptor_range) +Ptr Shader::Create(Type type, Context& context, const Settings& settings) { ITT_FUNCTION_TASK(); - - const DescriptorHeap::Type expected_heap_type = GetDescriptorHeapType(); - if (descriptor_range.heap_type != expected_heap_type) - { - throw std::runtime_error("Descriptor heap type \"" + DescriptorHeap::GetTypeName(descriptor_range.heap_type) + - "\" is incompatible with the resource binding, expected heap type is \"" + - DescriptorHeap::GetTypeName(expected_heap_type) + "\"."); - } - if (descriptor_range.count < m_settings_dx.base.resource_count) - { - throw std::runtime_error("Descriptor range size (" + std::to_string(descriptor_range.count) + - ") will not fit bound shader resources (" + std::to_string(m_settings_dx.base.resource_count) + ")."); - } - m_descriptor_range = descriptor_range; -} - -ContextDX& ShaderDX::ResourceBindingDX::GetContextDX() -{ - ITT_FUNCTION_TASK(); - return static_cast(m_context); -} - -Shader::Ptr Shader::Create(Type type, Context& context, const Settings& settings) -{ - ITT_FUNCTION_TASK(); - return std::make_shared(type, static_cast(context), settings); + return std::make_shared(type, dynamic_cast(context), settings); } ShaderDX::ShaderDX(Type type, ContextBase& context, const Settings& settings) @@ -297,57 +202,53 @@ ShaderDX::ShaderDX(Type type, ContextBase& context, const Settings& settings) #endif std::vector macro_definitions; - for (const auto& definition : m_settings.compile_definitions) + for (const auto& definition : settings.compile_definitions) { macro_definitions.push_back({ definition.first.c_str(), definition.second.c_str() }); } macro_definitions.push_back({ nullptr, nullptr }); - wrl::ComPtr error_blob; - if (!m_settings.source_file_path.empty()) + if (!settings.source_file_path.empty()) { + wrl::ComPtr error_blob; ThrowIfFailed(D3DCompileFromFile( - nowide::widen(m_settings.source_file_path).c_str(), + nowide::widen(settings.source_file_path).c_str(), macro_definitions.data(), D3D_COMPILE_STANDARD_FILE_INCLUDE, - m_settings.entry_function.function_name.c_str(), - m_settings.source_compile_target.c_str(), + settings.entry_function.function_name.c_str(), + settings.source_compile_target.c_str(), shader_compile_flags, 0, &m_cp_byte_code, &error_blob ), error_blob); + + m_sp_byte_code_chunk = std::make_unique(static_cast(m_cp_byte_code->GetBufferPointer()), + static_cast(m_cp_byte_code->GetBufferSize())); } else { const std::string compiled_func_name = GetCompiledEntryFunctionName(); - const Data::Chunk compiled_func_data = m_settings.data_provider.GetData(compiled_func_name + ".obj"); - - ThrowIfFailed(D3DCreateBlob(compiled_func_data.size, &m_cp_byte_code)); - Data::RawPtr p_cp_byte_code_data = static_cast(m_cp_byte_code->GetBufferPointer()); - std::copy(compiled_func_data.p_data, compiled_func_data.p_data + compiled_func_data.size, p_cp_byte_code_data); + m_sp_byte_code_chunk = std::make_unique(settings.data_provider.GetData(compiled_func_name + ".obj")); } - ThrowIfFailed(D3DReflect( - m_cp_byte_code->GetBufferPointer(), - m_cp_byte_code->GetBufferSize(), - IID_PPV_ARGS(&m_cp_reflection) - )); + assert(!!m_sp_byte_code_chunk); + ThrowIfFailed(D3DReflect(m_sp_byte_code_chunk->p_data, m_sp_byte_code_chunk->size, IID_PPV_ARGS(&m_cp_reflection))); } -ShaderBase::ResourceBindings ShaderDX::GetResourceBindings(const std::set& constant_argument_names, const std::set& addressable_argument_names) const +ShaderBase::ArgumentBindings ShaderDX::GetArgumentBindings(const Program::ArgumentDescriptions& argument_descriptions) const { ITT_FUNCTION_TASK(); assert(!!m_cp_reflection); - ShaderBase::ResourceBindings resource_bindings; + ShaderBase::ArgumentBindings argument_bindings; D3D12_SHADER_DESC shader_desc = { }; m_cp_reflection->GetDesc(&shader_desc); #ifdef _DEBUG std::stringstream log_ss; - log_ss << std::endl << GetTypeName() << " shader v." << shader_desc.Version << " created by \"" << shader_desc.Creator << "\" with resource bindings:" << std::endl; + log_ss << std::endl << GetTypeName() << " shader v." << shader_desc.Version << " with argument bindings:" << std::endl; #endif for (UINT resource_index = 0; resource_index < shader_desc.BoundResources; ++resource_index) @@ -355,23 +256,24 @@ ShaderBase::ResourceBindings ShaderDX::GetResourceBindings(const std::setGetResourceBindingDesc(resource_index, &binding_desc)); - const std::string argument_name(binding_desc.Name); - const bool is_constant_binding = constant_argument_names.find(argument_name) != constant_argument_names.end(); - const bool is_addressable_binding = addressable_argument_names.find(argument_name) != addressable_argument_names.end(); - const ResourceBindingDX::Type dx_binding_type = !is_addressable_binding ? ResourceBindingDX::Type::DescriptorTable - : (binding_desc.Type == D3D_SIT_CBUFFER ? ResourceBindingDX::Type::ConstantBufferView - : ResourceBindingDX::Type::ShaderResourceView); - resource_bindings.push_back(std::make_shared( - m_context, - ResourceBindingDX::Settings + const Program::Argument shader_argument(GetType(), binding_desc.Name); + const auto argument_desc_it = Program::FindArgumentDescription(argument_descriptions, shader_argument); + const Program::ArgumentDesc argument_desc = argument_desc_it == argument_descriptions.end() + ? Program::ArgumentDesc(shader_argument) + : *argument_desc_it; + const ProgramBindingsDX::ArgumentBindingDX::Type dx_binding_type = argument_desc.IsAddressable() + ? binding_desc.Type == D3D_SIT_CBUFFER ? ProgramBindingsDX::ArgumentBindingDX::Type::ConstantBufferView + : ProgramBindingsDX::ArgumentBindingDX::Type::ShaderResourceView + : ProgramBindingsDX::ArgumentBindingDX::Type::DescriptorTable; + + argument_bindings.push_back(std::make_shared( + GetContext(), + ProgramBindingsDX::ArgumentBindingDX::SettingsDX { { - m_type, - argument_name, + argument_desc, GetResourceTypeByInputType(binding_desc.Type), - binding_desc.BindCount, - is_constant_binding, - is_addressable_binding + binding_desc.BindCount }, dx_binding_type, binding_desc.Type, @@ -381,18 +283,22 @@ ShaderBase::ResourceBindings ShaderDX::GetResourceBindings(const std::set ShaderDX::GetNativeProgramInputLayout(const ProgramDX& program) const @@ -457,7 +363,7 @@ std::vector ShaderDX::GetNativeProgramInputLayout(cons element_desc.InputSlot = buffer_index; element_desc.InputSlotClass = GetInputClassificationByLayoutStepType(input_buffer_layout.step_type); element_desc.InstanceDataStepRate = 0; // FIXME: input_buffer_layout.step_rate; - element_desc.Format = TypeConverterDX::ParameterDescToDXGIFormatAndSize(param_desc, element_byte_size); + element_desc.Format = TypeConverterDX::ParameterDescToDxgiFormatAndSize(param_desc, element_byte_size); element_desc.AlignedByteOffset = buffer_byte_offset; dx_input_layout.push_back(element_desc); @@ -471,10 +377,10 @@ std::vector ShaderDX::GetNativeProgramInputLayout(cons return dx_input_layout; } -ContextDX& ShaderDX::GetContextDX() +IContextDX& ShaderDX::GetContextDX() noexcept { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(GetContext()); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ShaderDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ShaderDX.h index 55f8381d8..0e7a9f8f7 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ShaderDX.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/ShaderDX.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,93 +24,38 @@ DirectX 12 implementation of the shader interface. #pragma once #include +#include #include "DescriptorHeapDX.h" -#include "ResourceDX.h" #include #include #include #include -#include - namespace Methane::Graphics { namespace wrl = Microsoft::WRL; -class ContextDX; +struct IContextDX; class ProgramDX; class ShaderDX final : public ShaderBase { public: - class ResourceBindingDX : public ResourceBindingBase - { - public: - enum class Type : uint32_t - { - DescriptorTable = 0, - ConstantBufferView, - ShaderResourceView, - }; - - struct Settings - { - ResourceBindingBase::Settings base; - Type type; - D3D_SHADER_INPUT_TYPE input_type; - uint32_t point; - uint32_t space; - }; - - struct DescriptorRange - { - DescriptorHeap::Type heap_type = DescriptorHeap::Type::Undefined; - uint32_t offset = 0; - uint32_t count = 0; - }; - - ResourceBindingDX(ContextBase& context, const Settings& settings); - ResourceBindingDX(const ResourceBindingDX& other); - - // ResourceBinding interface - void SetResourceLocations(const Resource::Locations& resource_locations) override; - bool IsAddressable() const override { return m_settings_dx.type != Type::DescriptorTable; } - - const Settings& GetSettings() const noexcept { return m_settings_dx; } - uint32_t GetRootParameterIndex() const noexcept { return m_root_parameter_index; } - const DescriptorRange& GetDescriptorRange() const noexcept { return m_descriptor_range; } - const ResourceDX::LocationsDX& GetResourceLocationsDX() const noexcept { return m_resource_locations_dx; } - - void SetRootParameterIndex(uint32_t root_parameter_index) { m_root_parameter_index = root_parameter_index; } - void SetDescriptorRange(const DescriptorRange& descriptor_range); - void SetDescriptorHeapReservation(const DescriptorHeap::Reservation* p_descriptor_heap_reservation) - { m_p_descriptor_heap_reservation = p_descriptor_heap_reservation; } - - protected: - ContextDX& GetContextDX(); - - const Settings m_settings_dx; - uint32_t m_root_parameter_index = std::numeric_limits::max();; - DescriptorRange m_descriptor_range; - const DescriptorHeap::Reservation* m_p_descriptor_heap_reservation = nullptr; - ResourceDX::LocationsDX m_resource_locations_dx; - }; - ShaderDX(Type type, ContextBase& context, const Settings& settings); - // ShaderBase - ResourceBindings GetResourceBindings(const std::set& constant_argument_names, - const std::set& addressable_argument_names) const override; + // ShaderBase overrides + ArgumentBindings GetArgumentBindings(const Program::ArgumentDescriptions& argument_descriptions) const override; - const wrl::ComPtr& GetNativeByteCode() const noexcept { return m_cp_byte_code; } + const Data::Chunk* GetNativeByteCode() const noexcept { return m_sp_byte_code_chunk.get(); } std::vector GetNativeProgramInputLayout(const ProgramDX& program) const; -protected: - ContextDX& GetContextDX(); +private: + IContextDX& GetContextDX() noexcept; + UniquePtr m_sp_byte_code_chunk; wrl::ComPtr m_cp_byte_code; wrl::ComPtr m_cp_reflection; }; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/TextureDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/TextureDX.cpp index 8eb49ca31..28b01efab 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/TextureDX.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/TextureDX.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,14 +22,14 @@ DirectX 12 implementation of the texture interface. ******************************************************************************/ #include "TextureDX.h" -#include "ContextDX.h" +#include "RenderContextDX.h" #include "DeviceDX.h" #include "DescriptorHeapDX.h" #include "CommandQueueDX.h" -#include "RenderCommandListDX.h" +#include "BlitCommandListDX.h" #include "TypesDX.h" -#include +#include #include #include @@ -56,48 +56,48 @@ static D3D12_DSV_DIMENSION GetDsvDimension(const Dimensions& tex_dimensions) : D3D12_DSV_DIMENSION_TEXTURE2D; } -Texture::Ptr Texture::CreateRenderTarget(Context& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage) +Ptr Texture::CreateRenderTarget(RenderContext& render_context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); switch (settings.type) { case Texture::Type::FrameBuffer: throw std::logic_error("Frame buffer texture must be created with static method Texture::CreateFrameBuffer."); - case Texture::Type::DepthStencilBuffer: return std::make_shared(static_cast(context), settings, descriptor_by_usage, context.GetSettings().clear_depth_stencil); - default: return std::make_shared(static_cast(context), settings, descriptor_by_usage); + case Texture::Type::DepthStencilBuffer: return std::make_shared(static_cast(render_context), settings, descriptor_by_usage, render_context.GetSettings().clear_depth_stencil); + default: return std::make_shared(static_cast(render_context), settings, descriptor_by_usage); } } -Texture::Ptr Texture::CreateFrameBuffer(Context& context, uint32_t frame_buffer_index, const DescriptorByUsage& descriptor_by_usage) +Ptr Texture::CreateFrameBuffer(RenderContext& render_context, uint32_t frame_buffer_index, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); - const Context::Settings& context_settings = context.GetSettings(); + const RenderContext::Settings& context_settings = render_context.GetSettings(); const Settings texture_settings = Settings::FrameBuffer(context_settings.frame_size, context_settings.color_format); - return std::make_shared(static_cast(context), texture_settings, descriptor_by_usage, frame_buffer_index); + return std::make_shared(static_cast(render_context), texture_settings, descriptor_by_usage, frame_buffer_index); } -Texture::Ptr Texture::CreateDepthStencilBuffer(Context& context, const DescriptorByUsage& descriptor_by_usage) +Ptr Texture::CreateDepthStencilBuffer(RenderContext& render_context, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); - const Context::Settings& context_settings = context.GetSettings(); + const RenderContext::Settings& context_settings = render_context.GetSettings(); const Settings texture_settings = Settings::DepthStencilBuffer(context_settings.frame_size, context_settings.depth_stencil_format); - return std::make_shared(static_cast(context), texture_settings, descriptor_by_usage, context_settings.clear_depth_stencil); + return std::make_shared(static_cast(render_context), texture_settings, descriptor_by_usage, context_settings.clear_depth_stencil); } -Texture::Ptr Texture::CreateImage(Context& context, const Dimensions& dimensions, uint32_t array_length, PixelFormat pixel_format, bool mipmapped, const DescriptorByUsage& descriptor_by_usage) +Ptr Texture::CreateImage(Context& render_context, const Dimensions& dimensions, uint32_t array_length, PixelFormat pixel_format, bool mipmapped, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); const Settings texture_settings = Settings::Image(dimensions, array_length, pixel_format, mipmapped, Usage::ShaderRead); - return std::make_shared(static_cast(context), texture_settings, descriptor_by_usage, ImageTextureArg()); + return std::make_shared(dynamic_cast(render_context), texture_settings, descriptor_by_usage, ImageTextureArg()); } -Texture::Ptr Texture::CreateCube(Context& context, uint32_t dimension_size, uint32_t array_length, PixelFormat pixel_format, bool mipmapped, const DescriptorByUsage& descriptor_by_usage) +Ptr Texture::CreateCube(Context& render_context, uint32_t dimension_size, uint32_t array_length, PixelFormat pixel_format, bool mipmapped, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); const Settings texture_settings = Settings::Cube(dimension_size, array_length, pixel_format, mipmapped, Usage::ShaderRead); - return std::make_shared(static_cast(context), texture_settings, descriptor_by_usage, ImageTextureArg()); + return std::make_shared(dynamic_cast(render_context), texture_settings, descriptor_by_usage, ImageTextureArg()); } template<> @@ -105,14 +105,16 @@ void RenderTargetTextureDX::Initialize() { ITT_FUNCTION_TASK(); - if (m_settings.dimensions.depth != 1 || m_settings.dimensions.width == 0 || m_settings.dimensions.height == 0) + const Settings& settings = GetSettings(); + if (settings.dimensions.depth != 1 || settings.dimensions.width == 0 || settings.dimensions.height == 0) { - throw std::invalid_argument("Render target texture can only be created for 2D texture with dimensions.depth == 1 and non zero width and hight."); + throw std::invalid_argument("Render target texture can only be created for 2D texture with dimensions.depth == 1 and non zero width and height."); } D3D12_RESOURCE_DESC tex_desc = CD3DX12_RESOURCE_DESC::Tex2D( - TypeConverterDX::DataFormatToDXGI(m_settings.pixel_format), - m_settings.dimensions.width, m_settings.dimensions.height + TypeConverterDX::DataFormatToDXGI(settings.pixel_format), + settings.dimensions.width, + settings.dimensions.height ); InitializeCommittedResource(tex_desc, D3D12_HEAP_TYPE_DEFAULT, D3D12_RESOURCE_STATE_GENERIC_READ); } @@ -124,14 +126,13 @@ void FrameBufferTextureDX::Initialize(uint32_t frame_buffer_index) InitializeFrameBufferResource(frame_buffer_index); - if (m_usage_mask != Usage::RenderTarget) + if (GetUsageMask() != Usage::RenderTarget) { throw std::runtime_error("Frame BufferBase texture supports only Render Target usage."); } - assert(!!m_cp_resource); - const D3D12_CPU_DESCRIPTOR_HANDLE descriptor_handle = GetNativeCPUDescriptorHandle(Usage::RenderTarget); - GetContextDX().GetDeviceDX().GetNativeDevice()->CreateRenderTargetView(m_cp_resource.Get(), nullptr, descriptor_handle); + const D3D12_CPU_DESCRIPTOR_HANDLE descriptor_handle = GetNativeCpuDescriptorHandle(Usage::RenderTarget); + GetContextDX().GetDeviceDX().GetNativeDevice()->CreateRenderTargetView(GetNativeResource(), nullptr, descriptor_handle); } template<> @@ -139,23 +140,24 @@ void DepthStencilBufferTextureDX::Initialize(const std::optional& { ITT_FUNCTION_TASK(); + const Settings& settings = GetSettings(); CD3DX12_RESOURCE_DESC tex_desc = CD3DX12_RESOURCE_DESC::Tex2D( - TypeConverterDX::DataFormatToDXGI(m_settings.pixel_format, TypeConverterDX::ResourceFormatType::ResourceBase), - m_settings.dimensions.width, m_settings.dimensions.height + TypeConverterDX::DataFormatToDXGI(settings.pixel_format, TypeConverterDX::ResourceFormatType::ResourceBase), + settings.dimensions.width, settings.dimensions.height ); tex_desc.Flags = D3D12_RESOURCE_FLAG_NONE; - if (m_settings.usage_mask & Usage::RenderTarget) + if (settings.usage_mask & Usage::RenderTarget) { tex_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; } - if (!(m_settings.usage_mask & Usage::ShaderRead || - m_settings.usage_mask & Usage::ShaderWrite)) + if (!(settings.usage_mask & Usage::ShaderRead || + settings.usage_mask & Usage::ShaderWrite)) { tex_desc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; } - const DXGI_FORMAT view_write_format = TypeConverterDX::DataFormatToDXGI(m_settings.pixel_format, TypeConverterDX::ResourceFormatType::ViewWrite); + const DXGI_FORMAT view_write_format = TypeConverterDX::DataFormatToDXGI(settings.pixel_format, TypeConverterDX::ResourceFormatType::ViewWrite); if (clear_depth_stencil) { @@ -170,9 +172,10 @@ void DepthStencilBufferTextureDX::Initialize(const std::optional& const wrl::ComPtr& cp_device = GetContextDX().GetDeviceDX().GetNativeDevice(); + const Usage::Mask usage_mask = GetUsageMask(); for (Usage::Value usage : Usage::primary_values) { - if (!(m_usage_mask & usage)) + if (!(usage_mask & usage)) continue; const Descriptor& desc = ResourceBase::GetDescriptorByUsage(usage); @@ -181,19 +184,19 @@ void DepthStencilBufferTextureDX::Initialize(const std::optional& case DescriptorHeap::Type::ShaderResources: { D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {}; - srv_desc.Format = TypeConverterDX::DataFormatToDXGI(m_settings.pixel_format, TypeConverterDX::ResourceFormatType::ViewRead); - srv_desc.ViewDimension = GetSrvDimension(m_settings.dimensions); + srv_desc.Format = TypeConverterDX::DataFormatToDXGI(settings.pixel_format, TypeConverterDX::ResourceFormatType::ViewRead); + srv_desc.ViewDimension = GetSrvDimension(settings.dimensions); srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srv_desc.Texture2D.MipLevels = 1; - cp_device->CreateShaderResourceView(m_cp_resource.Get(), &srv_desc, GetNativeCPUDescriptorHandle(desc)); + cp_device->CreateShaderResourceView(GetNativeResource(), &srv_desc, GetNativeCpuDescriptorHandle(desc)); } break; case DescriptorHeap::Type::DepthStencil: { D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = {}; dsv_desc.Format = view_write_format; - dsv_desc.ViewDimension = GetDsvDimension(m_settings.dimensions); - cp_device->CreateDepthStencilView(m_cp_resource.Get(), &dsv_desc, GetNativeCPUDescriptorHandle(desc)); + dsv_desc.ViewDimension = GetDsvDimension(settings.dimensions); + cp_device->CreateDepthStencilView(GetNativeResource(), &dsv_desc, GetNativeCpuDescriptorHandle(desc)); } break; default: @@ -202,12 +205,12 @@ void DepthStencilBufferTextureDX::Initialize(const std::optional& } } -ImageTextureDX::TextureDX(ContextBase& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage, ImageTextureArg) - : TextureBase(context, settings, descriptor_by_usage) +ImageTextureDX::TextureDX(ContextBase& render_context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage, ImageTextureArg) + : TextureBase(render_context, settings, descriptor_by_usage) { ITT_FUNCTION_TASK(); - if (m_usage_mask != Usage::ShaderRead) + if (ResourceBase::GetUsageMask() != Usage::ShaderRead) { throw std::runtime_error("Image texture supports only \"Shader Read\" usage."); } @@ -219,7 +222,7 @@ ImageTextureDX::TextureDX(ContextBase& context, const Settings& settings, const const wrl::ComPtr& cp_device = GetContextDX().GetDeviceDX().GetNativeDevice(); const UINT number_of_subresources = GetRequiredSubresourceCount(); - const UINT64 upload_buffer_size = GetRequiredIntermediateSize(m_cp_resource.Get(), 0, number_of_subresources); + const UINT64 upload_buffer_size = GetRequiredIntermediateSize(GetNativeResource(), 0, number_of_subresources); ThrowIfFailed( cp_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), @@ -231,23 +234,24 @@ ImageTextureDX::TextureDX(ContextBase& context, const Settings& settings, const ) ); - cp_device->CreateShaderResourceView(m_cp_resource.Get(), &tex_and_srv_desc.second, GetNativeCPUDescriptorHandle(Usage::ShaderRead)); + cp_device->CreateShaderResourceView(GetNativeResource(), &tex_and_srv_desc.second, GetNativeCpuDescriptorHandle(Usage::ShaderRead)); } ImageTextureDX::ResourceAndViewDesc ImageTextureDX::GetResourceAndViewDesc() const { - assert(m_settings.dimensions.depth > 0); - assert(m_settings.dimensions.width > 0); - assert(m_settings.dimensions.height > 0); + const Settings& settings = GetSettings(); + assert(settings.dimensions.depth > 0); + assert(settings.dimensions.width > 0); + assert(settings.dimensions.height > 0); D3D12_RESOURCE_DESC tex_desc = {}; D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {}; const uint32_t mip_levels_count = GetMipLevelsCount(); - switch (m_settings.dimension_type) + switch (settings.dimension_type) { case DimensionType::Tex1D: - if (m_settings.array_length != 1) + if (settings.array_length != 1) { throw std::invalid_argument("Single 1D Texture must have array length equal to 1."); } @@ -255,27 +259,27 @@ ImageTextureDX::ResourceAndViewDesc ImageTextureDX::GetResourceAndViewDesc() con // NOTE: break is missing intentionally case DimensionType::Tex1DArray: - if (m_settings.dimensions.height != 1 || m_settings.dimensions.depth != 1) + if (settings.dimensions.height != 1 || settings.dimensions.depth != 1) { throw std::invalid_argument("1D Textures must have height and depth dimensions equal to 1."); } tex_desc = CD3DX12_RESOURCE_DESC::Tex1D( - TypeConverterDX::DataFormatToDXGI(m_settings.pixel_format), - m_settings.dimensions.width, - m_settings.array_length, + TypeConverterDX::DataFormatToDXGI(settings.pixel_format), + settings.dimensions.width, + settings.array_length, mip_levels_count ); srv_desc.Texture1DArray.MipLevels = mip_levels_count; - srv_desc.Texture1DArray.ArraySize = m_settings.array_length; - srv_desc.ViewDimension = m_settings.dimension_type == DimensionType::Tex1D + srv_desc.Texture1DArray.ArraySize = settings.array_length; + srv_desc.ViewDimension = settings.dimension_type == DimensionType::Tex1D ? D3D12_SRV_DIMENSION_TEXTURE1D : D3D12_SRV_DIMENSION_TEXTURE1DARRAY; break; case DimensionType::Tex2D: - if (m_settings.array_length != 1) + if (settings.array_length != 1) { throw std::invalid_argument("Single 2D Texture must have array length equal to 1."); } @@ -283,35 +287,35 @@ ImageTextureDX::ResourceAndViewDesc ImageTextureDX::GetResourceAndViewDesc() con // NOTE: break is missing intentionally case DimensionType::Tex2DArray: - if (m_settings.dimensions.depth != 1) + if (settings.dimensions.depth != 1) { throw std::invalid_argument("2D Textures must have depth dimension equal to 1."); } tex_desc = CD3DX12_RESOURCE_DESC::Tex2D( - TypeConverterDX::DataFormatToDXGI(m_settings.pixel_format), - m_settings.dimensions.width, - m_settings.dimensions.height, - m_settings.array_length, + TypeConverterDX::DataFormatToDXGI(settings.pixel_format), + settings.dimensions.width, + settings.dimensions.height, + settings.array_length, mip_levels_count ); srv_desc.Texture2DArray.MipLevels = mip_levels_count; - srv_desc.Texture2DArray.ArraySize = m_settings.array_length; - srv_desc.ViewDimension = m_settings.dimension_type == DimensionType::Tex2D + srv_desc.Texture2DArray.ArraySize = settings.array_length; + srv_desc.ViewDimension = settings.dimension_type == DimensionType::Tex2D ? D3D12_SRV_DIMENSION_TEXTURE2D : D3D12_SRV_DIMENSION_TEXTURE2DARRAY; break; case DimensionType::Tex3D: - if (m_settings.array_length != 1) + if (settings.array_length != 1) { throw std::invalid_argument("Single 3D Texture must have array length equal to 1."); } tex_desc = CD3DX12_RESOURCE_DESC::Tex3D( - TypeConverterDX::DataFormatToDXGI(m_settings.pixel_format), - m_settings.dimensions.width, - m_settings.dimensions.height, - m_settings.dimensions.depth, + TypeConverterDX::DataFormatToDXGI(settings.pixel_format), + settings.dimensions.width, + settings.dimensions.height, + settings.dimensions.depth, mip_levels_count ); srv_desc.Texture3D.MipLevels = mip_levels_count; @@ -319,7 +323,7 @@ ImageTextureDX::ResourceAndViewDesc ImageTextureDX::GetResourceAndViewDesc() con break; case DimensionType::Cube: - if (m_settings.array_length != 1) + if (settings.array_length != 1) { throw std::invalid_argument("Single Cube Texture must have array length equal to 1."); } @@ -327,22 +331,22 @@ ImageTextureDX::ResourceAndViewDesc ImageTextureDX::GetResourceAndViewDesc() con // NOTE: break is missing intentionally case DimensionType::CubeArray: - if (m_settings.dimensions.depth != 6) + if (settings.dimensions.depth != 6) { throw std::invalid_argument("Cube textures must have depth dimension equal to 6."); } tex_desc = CD3DX12_RESOURCE_DESC::Tex2D( - TypeConverterDX::DataFormatToDXGI(m_settings.pixel_format), - m_settings.dimensions.width, - m_settings.dimensions.height, - m_settings.dimensions.depth * m_settings.array_length, + TypeConverterDX::DataFormatToDXGI(settings.pixel_format), + settings.dimensions.width, + settings.dimensions.height, + settings.dimensions.depth * settings.array_length, mip_levels_count ); srv_desc.TextureCubeArray.First2DArrayFace = 0; - srv_desc.TextureCubeArray.NumCubes = m_settings.array_length; + srv_desc.TextureCubeArray.NumCubes = settings.array_length; srv_desc.TextureCubeArray.MipLevels = mip_levels_count; - srv_desc.ViewDimension = m_settings.dimension_type == DimensionType::Cube + srv_desc.ViewDimension = settings.dimension_type == DimensionType::Cube ? D3D12_SRV_DIMENSION_TEXTURECUBE : D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; break; @@ -365,14 +369,14 @@ void ImageTextureDX::SetData(const SubResources& sub_resources) m_data_size = 0; - assert(!!m_cp_resource); assert(!!m_cp_upload_resource); - const Data::Size pixel_size = GetPixelSize(m_settings.pixel_format); - const uint32_t mip_levels_count = GetMipLevelsCount(); - const uint32_t required_subresources_count = GetRequiredSubresourceCount(); + const Settings& settings = GetSettings(); + const Data::Size pixel_size = GetPixelSize(settings.pixel_format); + const uint32_t mip_levels_count = GetMipLevelsCount(); + const uint32_t required_subresources_count = GetRequiredSubresourceCount(); - if (!m_settings.mipmapped && sub_resources.size() < required_subresources_count) + if (!settings.mipmapped && sub_resources.size() < required_subresources_count) { throw std::invalid_argument("Number of sub-resources provided (" + std::to_string(sub_resources.size()) + ") is less than required (" + std::to_string(required_subresources_count) + @@ -382,15 +386,15 @@ void ImageTextureDX::SetData(const SubResources& sub_resources) std::vector dx_sub_resources(required_subresources_count, D3D12_SUBRESOURCE_DATA{}); for(const SubResource& sub_resource : sub_resources) { - const uint32_t sub_resource_raw_index = sub_resource.GetRawIndex(m_settings.dimensions.depth, mip_levels_count); + const uint32_t sub_resource_raw_index = sub_resource.GetRawIndex(settings.dimensions.depth, mip_levels_count); assert(sub_resource_raw_index < dx_sub_resources.size()); if (sub_resource_raw_index >= dx_sub_resources.size()) continue; D3D12_SUBRESOURCE_DATA& dx_sub_resource = dx_sub_resources[sub_resource_raw_index]; dx_sub_resource.pData = sub_resource.p_data; - dx_sub_resource.RowPitch = m_settings.dimensions.width * pixel_size; - dx_sub_resource.SlicePitch = m_settings.dimensions.height * dx_sub_resource.RowPitch; + dx_sub_resource.RowPitch = settings.dimensions.width * pixel_size; + dx_sub_resource.SlicePitch = settings.dimensions.height * dx_sub_resource.RowPitch; if (dx_sub_resource.SlicePitch > static_cast(sub_resource.data_size)) { @@ -402,15 +406,14 @@ void ImageTextureDX::SetData(const SubResources& sub_resources) // NOTE: scratch_image is the owner of generated mip-levels memory, which should be hold until UpdateSubresources call completes DirectX::ScratchImage scratch_image; - if (m_settings.mipmapped && sub_resources.size() < required_subresources_count) + if (settings.mipmapped && sub_resources.size() < required_subresources_count) { GenerateMipLevels(dx_sub_resources, scratch_image); } - RenderCommandListDX& upload_cmd_list = static_cast(m_context.GetUploadCommandList()); - DirectX:: ScratchImage mipChain; - UpdateSubresources(upload_cmd_list.GetNativeCommandList().Get(), - m_cp_resource.Get(), m_cp_upload_resource.Get(), 0, 0, + BlitCommandListDX& upload_cmd_list = static_cast(GetContext().GetUploadCommandList()); + UpdateSubresources(&upload_cmd_list.GetNativeCommandList(), + GetNativeResource(), m_cp_upload_resource.Get(), 0, 0, static_cast(dx_sub_resources.size()), dx_sub_resources.data()); upload_cmd_list.SetResourceTransitionBarriers({ static_cast(*this) }, ResourceBase::State::CopyDest, ResourceBase::State::PixelShaderResource); @@ -420,9 +423,10 @@ void ImageTextureDX::GenerateMipLevels(std::vector& dx_s { ITT_FUNCTION_TASK(); - const uint32_t mip_levels_count = GetMipLevelsCount(); - const D3D12_RESOURCE_DESC tex_desc = m_cp_resource->GetDesc(); - const bool is_cube_texture = m_settings.dimension_type == DimensionType::Cube || m_settings.dimension_type == DimensionType::CubeArray; + const Settings& settings = GetSettings(); + const uint32_t mip_levels_count = GetMipLevelsCount(); + const D3D12_RESOURCE_DESC tex_desc = GetNativeResourceRef().GetDesc(); + const bool is_cube_texture = settings.dimension_type == DimensionType::Cube || settings.dimension_type == DimensionType::CubeArray; std::vector sub_resource_images(dx_sub_resources.size(), DirectX::Image{}); for(uint32_t sub_resource_raw_index = 0; sub_resource_raw_index < dx_sub_resources.size(); ++sub_resource_raw_index) @@ -434,8 +438,8 @@ void ImageTextureDX::GenerateMipLevels(std::vector& dx_s D3D12_SUBRESOURCE_DATA& dx_sub_resource = dx_sub_resources[sub_resource_raw_index]; DirectX::Image& base_mip_image = sub_resource_images[sub_resource_raw_index]; - base_mip_image.width = m_settings.dimensions.width; - base_mip_image.height = m_settings.dimensions.height; + base_mip_image.width = settings.dimensions.width; + base_mip_image.height = settings.dimensions.height; base_mip_image.format = tex_desc.Format; base_mip_image.rowPitch = dx_sub_resource.RowPitch; base_mip_image.slicePitch = dx_sub_resource.SlicePitch; @@ -443,10 +447,10 @@ void ImageTextureDX::GenerateMipLevels(std::vector& dx_s } DirectX::TexMetadata tex_metadata = { }; - tex_metadata.width = m_settings.dimensions.width; - tex_metadata.height = m_settings.dimensions.height; - tex_metadata.depth = is_cube_texture ? 1 : m_settings.dimensions.depth; - tex_metadata.arraySize = is_cube_texture ? m_settings.dimensions.depth : m_settings.array_length; + tex_metadata.width = settings.dimensions.width; + tex_metadata.height = settings.dimensions.height; + tex_metadata.depth = is_cube_texture ? 1 : settings.dimensions.depth; + tex_metadata.arraySize = is_cube_texture ? settings.dimensions.depth : settings.array_length; tex_metadata.mipLevels = mip_levels_count; tex_metadata.format = tex_desc.Format; tex_metadata.dimension = static_cast(tex_desc.Dimension); diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/TextureDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/TextureDX.h index e65d284a1..4c73c227b 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/TextureDX.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/TextureDX.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ DirectX 12 implementation of the texture interface. #include #include #include -#include +#include #include @@ -69,10 +69,11 @@ class TextureDX : public TextureBase Data::Size GetDataSize() const override { ITT_FUNCTION_TASK(); - return m_settings.dimensions.GetPixelsCount() * GetPixelSize(m_settings.pixel_format); + const Settings& settings = GetSettings(); + return settings.dimensions.GetPixelsCount() * GetPixelSize(settings.pixel_format); } -protected: +private: void Initialize(ExtraArgs...); }; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/TypesDX.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/TypesDX.cpp index fd92f28f9..4a8e919cd 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/TypesDX.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/TypesDX.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,13 +17,13 @@ limitations under the License. ******************************************************************************* FILE: Methane/Graphics/DirectX12/TypesDX.h -Methane graphics types convertors to DirectX 12 native types. +Methane graphics types converters to DirectX 12 native types. ******************************************************************************/ #include "TypesDX.h" -#include +#include #include @@ -33,17 +33,17 @@ namespace Methane::Graphics CD3DX12_VIEWPORT TypeConverterDX::ViewportToD3D(const Viewport& viewport) noexcept { ITT_FUNCTION_TASK(); - return CD3DX12_VIEWPORT(static_cast(viewport.origin.x()), static_cast(viewport.origin.y()), + return CD3DX12_VIEWPORT(static_cast(viewport.origin.GetX()), static_cast(viewport.origin.GetY()), static_cast(viewport.size.width), static_cast(viewport.size.height), - static_cast(viewport.origin.z()), static_cast(viewport.origin.z() + viewport.size.depth)); + static_cast(viewport.origin.GetZ()), static_cast(viewport.origin.GetZ() + viewport.size.depth)); } CD3DX12_RECT TypeConverterDX::ScissorRectToD3D(const ScissorRect& scissor_rect) noexcept { ITT_FUNCTION_TASK(); - return CD3DX12_RECT(static_cast(scissor_rect.origin.x()), static_cast(scissor_rect.origin.y()), - static_cast(scissor_rect.origin.x() + scissor_rect.size.width), - static_cast(scissor_rect.origin.y() + scissor_rect.size.height)); + return CD3DX12_RECT(static_cast(scissor_rect.origin.GetX()), static_cast(scissor_rect.origin.GetY()), + static_cast(scissor_rect.origin.GetX() + scissor_rect.size.width), + static_cast(scissor_rect.origin.GetY() + scissor_rect.size.height)); } std::vector TypeConverterDX::ViewportsToD3D(const Viewports& viewports) noexcept @@ -106,6 +106,8 @@ DXGI_FORMAT TypeConverterDX::DataFormatToDXGI(const PixelFormat& data_format, Re case ResourceFormatType::ViewWrite: return DXGI_FORMAT_D32_FLOAT; } } break; + + default: assert(0); } return DataFormatToDXGI(data_format); } @@ -129,7 +131,7 @@ D3D12_COMPARISON_FUNC TypeConverterDX::CompareFunctionToDX(Compare compare_func) return D3D12_COMPARISON_FUNC_NEVER; } -DXGI_FORMAT TypeConverterDX::ParameterDescToDXGIFormatAndSize(const D3D12_SIGNATURE_PARAMETER_DESC& param_desc, uint32_t& out_element_byte_size) noexcept +DXGI_FORMAT TypeConverterDX::ParameterDescToDxgiFormatAndSize(const D3D12_SIGNATURE_PARAMETER_DESC& param_desc, uint32_t& out_element_byte_size) noexcept { ITT_FUNCTION_TASK(); diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/TypesDX.h b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/TypesDX.h index 13a35673b..b282184a3 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/TypesDX.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/DirectX12/TypesDX.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ limitations under the License. ******************************************************************************* FILE: Methane/Graphics/DirectX12/TypesDX.h -Methane graphics types convertors to DirectX 12 native types. +Methane graphics types converters to DirectX 12 native types. ******************************************************************************/ @@ -50,7 +50,7 @@ class TypeConverterDX static DXGI_FORMAT DataFormatToDXGI(const PixelFormat& data_format) noexcept; static DXGI_FORMAT DataFormatToDXGI(const PixelFormat& data_format, ResourceFormatType format_type) noexcept; static D3D12_COMPARISON_FUNC CompareFunctionToDX(Compare compare_func) noexcept; - static DXGI_FORMAT ParameterDescToDXGIFormatAndSize(const D3D12_SIGNATURE_PARAMETER_DESC& param_desc, uint32_t& out_element_byte_size) noexcept; + static DXGI_FORMAT ParameterDescToDxgiFormatAndSize(const D3D12_SIGNATURE_PARAMETER_DESC& param_desc, uint32_t& out_element_byte_size) noexcept; private: TypeConverterDX() = default; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/FenceBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/FenceBase.cpp new file mode 100644 index 000000000..f0d51929e --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/FenceBase.cpp @@ -0,0 +1,68 @@ +/****************************************************************************** + +Copyright 2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/DirectX12/FenceDX.cpp +DirectX 12 fence wrapper. + +******************************************************************************/ + +#include "FenceBase.h" +#include "CommandQueueBase.h" + +#include + +#ifdef COMMAND_EXECUTION_LOGGING +#include +#endif +namespace Methane::Graphics +{ + +FenceBase::FenceBase(CommandQueueBase& command_queue) + : m_command_queue(command_queue) +{ + ITT_FUNCTION_TASK(); +} + +void FenceBase::Signal() +{ + ITT_FUNCTION_TASK(); + + m_value++; + +#ifdef COMMAND_EXECUTION_LOGGING + Platform::PrintToDebugOutput("SIGNAL fence \"" + GetName() + "\" with value " + std::to_string(m_value)); +#endif +} + +void FenceBase::Wait() +{ + ITT_FUNCTION_TASK(); + +#ifdef COMMAND_EXECUTION_LOGGING + Platform::PrintToDebugOutput("WAIT fence \"" + GetName() + "\" with value " + std::to_string(m_value)); +#endif +} + +void FenceBase::Flush() +{ + ITT_FUNCTION_TASK(); + Signal(); + Wait(); +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/FenceBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/FenceBase.h new file mode 100644 index 000000000..9566154e3 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/FenceBase.h @@ -0,0 +1,56 @@ +/****************************************************************************** + +Copyright 2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/FenceBase.h +Methane fence base implementation. + +******************************************************************************/ + +#pragma once + +#include +#include +#include + +namespace Methane::Graphics +{ + +class CommandQueueBase; + +class FenceBase + : public Fence + , public ObjectBase +{ +public: + FenceBase(CommandQueueBase& command_queue); + + // Fence overrides + void Signal() override; + void Wait() override; + void Flush() override; + +protected: + CommandQueueBase& GetCommandQueue() noexcept { return m_command_queue; } + uint64_t GetValue() const noexcept { return m_value; } + +private: + CommandQueueBase& m_command_queue; + uint64_t m_value = 0u; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/BlitCommandListMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/BlitCommandListMT.hh new file mode 100644 index 000000000..ac3e0bf4a --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/BlitCommandListMT.hh @@ -0,0 +1,70 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/BlitCommandListMT.hh +Metal implementation of the blit command list interface. + +******************************************************************************/ + +#pragma once + +#include +#include + +#import + +namespace Methane::Graphics +{ + +class CommandQueueMT; + +class BlitCommandListMT final + : public CommandListBase + , public BlitCommandList +{ +public: + BlitCommandListMT(CommandQueueBase& command_queue); + + // CommandList interface + void PushDebugGroup(const std::string& name) override; + void PopDebugGroup() override; + void Commit() override; + + // CommandListBase interface + void SetResourceBarriers(const ResourceBase::Barriers&) override { } + void Execute(uint32_t frame_index) override; + + // BlitCommandList interface + void Reset(const std::string& debug_group = "") override; + + // Object interface + void SetName(const std::string& label) override; + + id& GetNativeCommandBuffer() noexcept { return m_mtl_cmd_buffer; } + id& GetNativeBlitEncoder() noexcept { return m_mtl_blit_encoder; } + +private: + void InitializeCommandBuffer(); + + CommandQueueMT& GetCommandQueueMT() noexcept; + + id m_mtl_cmd_buffer = nil; + id m_mtl_blit_encoder = nil; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/BlitCommandListMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/BlitCommandListMT.mm new file mode 100644 index 000000000..35e4497c1 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/BlitCommandListMT.mm @@ -0,0 +1,146 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/BlitCommandListMT.mm +Metal implementation of the blit command list interface. + +******************************************************************************/ + +#include "BlitCommandListMT.hh" +#include "CommandQueueMT.hh" +#include "RenderContextMT.hh" + +#include +#include + +namespace Methane::Graphics +{ + +Ptr BlitCommandList::Create(CommandQueue& command_queue) +{ + ITT_FUNCTION_TASK(); + return std::make_shared(static_cast(command_queue)); +} + +BlitCommandListMT::BlitCommandListMT(CommandQueueBase& command_queue) + : CommandListBase(command_queue, CommandList::Type::Blit) +{ + ITT_FUNCTION_TASK(); +} + +void BlitCommandListMT::Reset(const std::string& debug_group) +{ + ITT_FUNCTION_TASK(); + if (m_mtl_blit_encoder) + return; + + if (!m_mtl_cmd_buffer) + { + m_mtl_cmd_buffer = [GetCommandQueueMT().GetNativeCommandQueue() commandBuffer]; + assert(m_mtl_cmd_buffer != nil); + + m_mtl_cmd_buffer.label = MacOS::ConvertToNsType(GetName()); + } + + assert(m_mtl_cmd_buffer != nil); + m_mtl_blit_encoder = [m_mtl_cmd_buffer blitCommandEncoder]; + + assert(m_mtl_blit_encoder != nil); + m_mtl_blit_encoder.label = MacOS::ConvertToNsType(GetName()); +} + +void BlitCommandListMT::SetName(const std::string& name) +{ + ITT_FUNCTION_TASK(); + + CommandListBase::SetName(name); + + NSString* ns_name = MacOS::ConvertToNsType(name); + + if (m_mtl_blit_encoder != nil) + { + m_mtl_blit_encoder.label = ns_name; + } + + if (m_mtl_cmd_buffer != nil) + { + m_mtl_cmd_buffer.label = ns_name; + } +} + +void BlitCommandListMT::PushDebugGroup(const std::string& name) +{ + ITT_FUNCTION_TASK(); + + assert(m_mtl_blit_encoder != nil); + NSString* ns_name = MacOS::ConvertToNsType(name); + [m_mtl_blit_encoder pushDebugGroup:ns_name]; +} + +void BlitCommandListMT::PopDebugGroup() +{ + ITT_FUNCTION_TASK(); + + assert(m_mtl_blit_encoder != nil); + [m_mtl_blit_encoder popDebugGroup]; +} + +void BlitCommandListMT::Commit() +{ + ITT_FUNCTION_TASK(); + + assert(!IsCommitted()); + + CommandListBase::Commit(); + + if (m_mtl_blit_encoder) + { + [m_mtl_blit_encoder endEncoding]; + m_mtl_blit_encoder = nil; + } + + if (!m_mtl_cmd_buffer) + return; + + [m_mtl_cmd_buffer enqueue]; +} + +void BlitCommandListMT::Execute(uint32_t frame_index) +{ + ITT_FUNCTION_TASK(); + + CommandListBase::Execute(frame_index); + + if (!m_mtl_cmd_buffer) + return; + + [m_mtl_cmd_buffer addCompletedHandler:^(id) { + Complete(frame_index); + }]; + + [m_mtl_cmd_buffer commit]; + m_mtl_cmd_buffer = nil; +} + +CommandQueueMT& BlitCommandListMT::GetCommandQueueMT() noexcept +{ + ITT_FUNCTION_TASK(); + return static_cast(GetCommandQueue()); +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/BufferMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/BufferMT.hh index 639e5c9fd..8904b205b 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/BufferMT.hh +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/BufferMT.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,11 +30,9 @@ Metal implementation of the buffer interface. namespace Methane::Graphics { -class BufferMT : public BufferBase +class BufferMT final : public BufferBase { public: - using Ptr = std::shared_ptr; - BufferMT(ContextBase& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); BufferMT(ContextBase& context, const Settings& settings, Data::Size stride, PixelFormat format, const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); ~BufferMT() override; @@ -51,7 +49,7 @@ public: const id& GetNativeBuffer() const noexcept { return m_mtl_buffer; } MTLIndexType GetNativeIndexType() const noexcept; -protected: +private: id m_mtl_buffer; Data::Size m_stride = 0; PixelFormat m_format = PixelFormat::Unknown; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/BufferMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/BufferMT.mm index 31269d8a3..41863ea6b 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/BufferMT.mm +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/BufferMT.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,11 +23,12 @@ #include "BufferMT.hh" #include "DeviceMT.hh" -#include "ContextMT.hh" +#include "ContextMT.h" #include "TypesMT.hh" -#include +#include #include +#include #include #include @@ -36,21 +37,21 @@ namespace Methane::Graphics { -Buffer::Ptr Buffer::CreateVertexBuffer(Context& context, Data::Size size, Data::Size stride) +Ptr Buffer::CreateVertexBuffer(Context& context, Data::Size size, Data::Size stride) { ITT_FUNCTION_TASK(); const Buffer::Settings settings = { Buffer::Type::Vertex, Usage::Unknown, size }; - return std::make_shared(static_cast(context), settings, stride, PixelFormat::Unknown); + return std::make_shared(dynamic_cast(context), settings, stride, PixelFormat::Unknown); } -Buffer::Ptr Buffer::CreateIndexBuffer(Context& context, Data::Size size, PixelFormat format) +Ptr Buffer::CreateIndexBuffer(Context& context, Data::Size size, PixelFormat format) { ITT_FUNCTION_TASK(); const Buffer::Settings settings = { Buffer::Type::Index, Usage::Unknown, size }; - return std::make_shared(static_cast(context), settings, 0, format); + return std::make_shared(dynamic_cast(context), settings, 0, format); } -Buffer::Ptr Buffer::CreateConstantBuffer(Context& context, Data::Size size, bool addressable, const DescriptorByUsage& descriptor_by_usage) +Ptr Buffer::CreateConstantBuffer(Context& context, Data::Size size, bool addressable, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); Usage::Mask usage_mask = Usage::ShaderRead; @@ -58,7 +59,7 @@ usage_mask |= Usage::Addressable; const Buffer::Settings settings = { Buffer::Type::Constant, usage_mask, size }; - return std::make_shared(static_cast(context), settings, descriptor_by_usage); + return std::make_shared(dynamic_cast(context), settings, descriptor_by_usage); } Data::Size Buffer::GetAlignedBufferSize(Data::Size size) noexcept @@ -88,7 +89,7 @@ BufferMT::~BufferMT() { ITT_FUNCTION_TASK(); - m_context.GetResourceManager().GetReleasePool().AddResource(*this); + GetContext().GetResourceManager().GetReleasePool().AddResource(*this); } void BufferMT::SetName(const std::string& name) @@ -96,7 +97,7 @@ ITT_FUNCTION_TASK(); BufferBase::SetName(name); - m_mtl_buffer.label = MacOS::ConvertToNSType(name); + m_mtl_buffer.label = MacOS::ConvertToNsType(name); } void BufferMT::SetData(const SubResources& sub_resources) @@ -107,7 +108,7 @@ assert(m_mtl_buffer != nil); Data::RawPtr p_resource_data = static_cast([m_mtl_buffer contents]); - assert(!!p_resource_data); + assert(p_resource_data != nullptr); Data::Size data_size = 0; for(const SubResource& sub_resource : sub_resources) diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/CommandQueueMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/CommandQueueMT.hh index e2d8a924e..50b50c1a6 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/CommandQueueMT.hh +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/CommandQueueMT.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,8 +30,8 @@ Metal implementation of the command queue interface. namespace Methane::Graphics { -class RenderPassMT; -class ContextMT; +struct IContextMT; +class RenderContextMT; class CommandQueueMT final : public CommandQueueBase { @@ -42,14 +42,15 @@ public: // Object interface void SetName(const std::string& name) override; - ContextMT& GetContextMT() noexcept; + IContextMT& GetContextMT() noexcept; + RenderContextMT& GetRenderContextMT(); id& GetNativeCommandQueue() noexcept { return m_mtl_command_queue; } -protected: +private: void Reset(); - id m_mtl_command_queue; + id m_mtl_command_queue = nil; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/CommandQueueMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/CommandQueueMT.mm index b8485345a..699a73cb9 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/CommandQueueMT.mm +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/CommandQueueMT.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,22 +23,22 @@ #include "CommandQueueMT.hh" #include "DeviceMT.hh" -#include "ContextMT.hh" +#include "RenderContextMT.hh" -#include +#include #include namespace Methane::Graphics { -CommandQueue::Ptr CommandQueue::Create(Context& context) +Ptr CommandQueue::Create(Context& context) { ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context)); + return std::make_shared(dynamic_cast(context)); } CommandQueueMT::CommandQueueMT(ContextBase& context) - : CommandQueueBase(context, true) + : CommandQueueBase(context) , m_mtl_command_queue([GetContextMT().GetDeviceMT().GetNativeDevice() newCommandQueue]) { ITT_FUNCTION_TASK(); @@ -47,8 +47,6 @@ CommandQueueMT::~CommandQueueMT() { ITT_FUNCTION_TASK(); - assert(!IsExecuting()); - [m_mtl_command_queue release]; } @@ -59,13 +57,24 @@ CommandQueueBase::SetName(name); assert(m_mtl_command_queue != nil); - m_mtl_command_queue.label = MacOS::ConvertToNSType(name); + m_mtl_command_queue.label = MacOS::ConvertToNsType(name); +} + +IContextMT& CommandQueueMT::GetContextMT() noexcept +{ + ITT_FUNCTION_TASK(); + return static_cast(GetContext()); } -ContextMT& CommandQueueMT::GetContextMT() noexcept +RenderContextMT& CommandQueueMT::GetRenderContextMT() { ITT_FUNCTION_TASK(); - return static_cast(m_context); + ContextBase& context = GetContext(); + if (context.GetType() != Context::Type::Render) + { + throw std::runtime_error("Incompatible context type."); + } + return static_cast(context); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ContextMT.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ContextMT.h new file mode 100644 index 000000000..6f4cba50d --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ContextMT.h @@ -0,0 +1,44 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/ContextMT.h +Metal context accessor interface for template class ContextMT + +******************************************************************************/ + +#pragma once + +#include + +#include + +namespace Methane::Graphics +{ + +class DeviceMT; +class CommandQueueMT; +class ProgramLibraryMT; + +struct IContextMT +{ + virtual DeviceMT& GetDeviceMT() noexcept = 0; + virtual CommandQueueMT& GetUploadCommandQueueMT() noexcept = 0; + virtual const Ptr& GetLibraryMT(const std::string& library_name = "") = 0; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ContextMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ContextMT.hh deleted file mode 100644 index c9e6964fb..000000000 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ContextMT.hh +++ /dev/null @@ -1,94 +0,0 @@ -/****************************************************************************** - -Copyright 2019 Evgeny Gorodetskiy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -******************************************************************************* - -FILE: Methane/Graphics/Metal/ContextMT.hh -Metal implementation of the context interface. - -******************************************************************************/ - -#pragma once - -#include - -#import -#import - -#include -#include - -namespace Methane::Graphics -{ - -struct CommandQueue; -class RenderPassMT; -class DeviceMT; -class CommandQueueMT; - -class ContextMT : public ContextBase -{ -public: - class LibraryMT - { - public: - using Ptr = std::shared_ptr; - - LibraryMT(ContextMT& metal_context, const std::string& library_name = ""); - ~LibraryMT(); - - id& Get() noexcept { return m_mtl_library; } - - private: - static NSString* GetFullPath(const std::string& library_name); - - NSError* m_ns_error = nil; - id m_mtl_library; - }; - - ContextMT(const Platform::AppEnvironment& env, DeviceBase& device, const Settings& settings); - ~ContextMT() override; - - // Context interface - bool ReadyToRender() const override; - void OnCommandQueueCompleted(CommandQueue& cmd_queue, uint32_t frame_index) override; - void WaitForGpu(WaitFor wait_for) override; - void Resize(const FrameSize& frame_size) override; - void Present() override; - bool SetVSyncEnabled(bool vsync_enabled) override; - bool SetFrameBuffersCount(uint32_t frame_buffers_count) override; - float GetContentScalingFactor() const override; - Platform::AppView GetAppView() const override { return { m_app_view }; } - - id GetNativeDrawable() { return m_app_view.currentDrawable; } - DeviceMT& GetDeviceMT(); - CommandQueueMT& GetRenderCommandQueueMT(); - const LibraryMT::Ptr& GetLibraryMT(const std::string& library_name = ""); - -protected: - // ContextBase overrides - void Release() override; - void Initialize(Device& device, bool deferred_heap_allocation) override; - - using LibraryByName = std::map; - - AppViewMT* m_app_view; - dispatch_semaphore_t m_dispatch_semaphore; - LibraryByName m_library_by_name; - id m_frame_capture_scope; -}; - -} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ContextMT.hpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ContextMT.hpp new file mode 100644 index 000000000..955bbc1ad --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ContextMT.hpp @@ -0,0 +1,83 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/ContextMT.hpp +Metal template implementation of the base context interface. + +******************************************************************************/ + +#pragma once + +#include "ContextMT.h" +#include "DeviceMT.hh" +#include "ProgramLibraryMT.hh" + +#include +#include + +#import + +#include + +namespace Methane::Graphics +{ + +struct CommandQueue; + +template>> +class ContextMT : public ContextBaseT +{ +public: + ContextMT(DeviceBase& device, const typename ContextBaseT::Settings& settings) + : ContextBaseT(device, settings) + { + ITT_FUNCTION_TASK(); + //ContextBase::m_resource_manager.Initialize({ true }); + } + + // IContextMT interface + + DeviceMT& GetDeviceMT() noexcept override + { + ITT_FUNCTION_TASK(); + return static_cast(ContextBase::GetDeviceBase()); + } + + CommandQueueMT& GetUploadCommandQueueMT() noexcept override + { + ITT_FUNCTION_TASK(); + return static_cast(ContextBase::GetUploadCommandQueue()); + } + + const Ptr& GetLibraryMT(const std::string& library_name) override + { + ITT_FUNCTION_TASK(); + const auto library_by_name_it = m_library_by_name.find(library_name); + if (library_by_name_it != m_library_by_name.end()) + return library_by_name_it->second; + + return m_library_by_name.emplace(library_name, std::make_shared(GetDeviceMT(), library_name)).first->second; + } + +private: + using LibraryByName = std::map>; + + LibraryByName m_library_by_name; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ContextMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ContextMT.mm deleted file mode 100644 index 13d5931ce..000000000 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ContextMT.mm +++ /dev/null @@ -1,225 +0,0 @@ -/****************************************************************************** - -Copyright 2019 Evgeny Gorodetskiy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -******************************************************************************* - -FILE: Methane/Graphics/Metal/ContextMT.mm -Metal implementation of the context interface. - -******************************************************************************/ - -#include "ContextMT.hh" -#include "DeviceMT.hh" -#include "RenderStateMT.hh" -#include "RenderPassMT.hh" -#include "CommandQueueMT.hh" -#include "TypesMT.hh" - -#include -#include -#include - -namespace Methane::Graphics -{ - -Context::Ptr Context::Create(const Platform::AppEnvironment& env, Device& device, const Context::Settings& settings) -{ - ITT_FUNCTION_TASK(); - return std::make_shared(env, static_cast(device), settings); -} - -ContextMT::ContextMT(const Platform::AppEnvironment& env, DeviceBase& device, const Context::Settings& settings) - : ContextBase(device, settings) - , m_app_view([[AppViewMT alloc] initWithFrame: TypeConverterMT::CreateNSRect(m_settings.frame_size) - appWindow: env.ns_app_delegate.window - device: GetDeviceMT().GetNativeDevice() - pixelFormat: TypeConverterMT::DataFormatToMetalPixelType(m_settings.color_format) - drawableCount: m_settings.frame_buffers_count - vsyncEnabled: Methane::MacOS::ConvertToNSType(m_settings.vsync_enabled) - unsyncRefreshInterval: 1.0 / m_settings.unsync_max_fps]) - , m_dispatch_semaphore(dispatch_semaphore_create(m_settings.frame_buffers_count)) - , m_frame_capture_scope([[MTLCaptureManager sharedCaptureManager] newCaptureScopeWithDevice:GetDeviceMT().GetNativeDevice()]) -{ - ITT_FUNCTION_TASK(); - - m_frame_capture_scope.label = Methane::MacOS::ConvertToNSType(device.GetName() + " Capture Scope"); - [MTLCaptureManager sharedCaptureManager].defaultCaptureScope = m_frame_capture_scope; - - // bind metal context with application delegate - m_app_view.delegate = env.ns_app_delegate; - env.ns_app_delegate.view = m_app_view; - - m_resource_manager.Initialize({ true }); - - // Start redrawing main view - m_app_view.redrawing = YES; -} - -ContextMT::~ContextMT() -{ - ITT_FUNCTION_TASK(); - - dispatch_release(m_dispatch_semaphore); - - [m_app_view release]; -} - -void ContextMT::Release() -{ - ITT_FUNCTION_TASK(); - - m_app_view.redrawing = NO; - - // FIXME: semaphore release causes a crash - // https://stackoverflow.com/questions/8287621/why-does-this-code-cause-exc-bad-instruction - //dispatch_release(m_dispatch_semaphore); - - ContextBase::Release(); -} - -void ContextMT::Initialize(Device& device, bool deferred_heap_allocation) -{ - ITT_FUNCTION_TASK(); - - m_dispatch_semaphore = dispatch_semaphore_create(m_settings.frame_buffers_count); - - ContextBase::Initialize(device, deferred_heap_allocation); - - m_app_view.redrawing = YES; -} - -bool ContextMT::ReadyToRender() const -{ - ITT_FUNCTION_TASK(); - return m_app_view.currentDrawable != nil; -} - -void ContextMT::OnCommandQueueCompleted(CommandQueue& /*cmd_queue*/, uint32_t /*frame_index*/) -{ - ITT_FUNCTION_TASK(); - - dispatch_semaphore_signal(m_dispatch_semaphore); -} - -void ContextMT::WaitForGpu(WaitFor wait_for) -{ - ITT_FUNCTION_TASK(); - - ContextBase::WaitForGpu(wait_for); - - dispatch_semaphore_wait(m_dispatch_semaphore, DISPATCH_TIME_FOREVER); - - ContextBase::OnGpuWaitComplete(wait_for); - - if (wait_for == WaitFor::FramePresented) - { - m_frame_buffer_index = (m_frame_buffer_index + 1) % m_settings.frame_buffers_count; - [m_frame_capture_scope beginScope]; - } -} - -void ContextMT::Resize(const FrameSize& frame_size) -{ - ITT_FUNCTION_TASK(); - ContextBase::Resize(frame_size); -} - -void ContextMT::Present() -{ - ITT_FUNCTION_TASK(); - ContextBase::Present(); - - [m_frame_capture_scope endScope]; - - OnCpuPresentComplete(); -} - -bool ContextMT::SetVSyncEnabled(bool vsync_enabled) -{ - ITT_FUNCTION_TASK(); - if (ContextBase::SetVSyncEnabled(vsync_enabled)) - { - m_app_view.vsyncEnabled = vsync_enabled ? YES : NO; - return true; - } - return false; -} - -bool ContextMT::SetFrameBuffersCount(uint32_t frame_buffers_count) -{ - ITT_FUNCTION_TASK(); - frame_buffers_count = std::min(std::max(2u, frame_buffers_count), 3u); // Metal supports only 2 or 3 drawable buffers - if (ContextBase::SetFrameBuffersCount(frame_buffers_count)) - { - m_app_view.drawableCount = frame_buffers_count; - return true; - } - return false; -} - -float ContextMT::GetContentScalingFactor() const -{ - ITT_FUNCTION_TASK(); - return m_app_view.appWindow.backingScaleFactor; -} - -DeviceMT& ContextMT::GetDeviceMT() -{ - ITT_FUNCTION_TASK(); - return static_cast(GetDevice()); -} - -CommandQueueMT& ContextMT::GetRenderCommandQueueMT() -{ - ITT_FUNCTION_TASK(); - return static_cast(ContextBase::GetRenderCommandQueue()); -} - -const ContextMT::LibraryMT::Ptr& ContextMT::GetLibraryMT(const std::string& library_name) -{ - ITT_FUNCTION_TASK(); - const auto library_by_name_it = m_library_by_name.find(library_name); - if (library_by_name_it != m_library_by_name.end()) - return library_by_name_it->second; - - return m_library_by_name.emplace(library_name, std::make_shared(*this, library_name)).first->second; -} - -NSString* ContextMT::LibraryMT::GetFullPath(const std::string& library_name) -{ - return MacOS::ConvertToNSType(Platform::GetResourceDir() + "/" + library_name + ".metallib"); -} - -ContextMT::LibraryMT::LibraryMT(ContextMT& metal_context, const std::string& library_name) - : m_mtl_library(library_name.empty() - ? [metal_context.GetDeviceMT().GetNativeDevice() newDefaultLibrary] - : [metal_context.GetDeviceMT().GetNativeDevice() newLibraryWithFile:GetFullPath(library_name) error:&m_ns_error]) -{ - ITT_FUNCTION_TASK(); - if (!m_mtl_library) - { - const std::string error_msg = MacOS::ConvertFromNSType([m_ns_error localizedDescription]); - throw std::runtime_error("Failed to create " + (library_name.empty() ? std::string("default") : library_name) + " Metal library: " + error_msg); - } -} - -ContextMT::LibraryMT::~LibraryMT() -{ - ITT_FUNCTION_TASK(); - [m_mtl_library release]; -} - -} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/DescriptorHeapMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/DescriptorHeapMT.hh index adb2d6859..a79eb3d02 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/DescriptorHeapMT.hh +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/DescriptorHeapMT.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,9 +28,7 @@ Metal "dummy" implementation of the descriptor heap. namespace Methane::Graphics { -class ContextBase; - -class DescriptorHeapMT : public DescriptorHeap +class DescriptorHeapMT final : public DescriptorHeap { public: DescriptorHeapMT(ContextBase& context, const Settings& settings); diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/DescriptorHeapMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/DescriptorHeapMT.mm index d787726ca..ad1d70fc3 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/DescriptorHeapMT.mm +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/DescriptorHeapMT.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,12 +23,12 @@ #include "DescriptorHeapMT.hh" -#include +#include namespace Methane::Graphics { -DescriptorHeap::Ptr DescriptorHeap::Create(ContextBase& context, const Settings& settings) +Ptr DescriptorHeap::Create(ContextBase& context, const Settings& settings) { ITT_FUNCTION_TASK(); return std::make_shared(context, settings); diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/DeviceMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/DeviceMT.hh index 6bf1584ca..5c825c17a 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/DeviceMT.hh +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/DeviceMT.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -40,7 +40,7 @@ public: id& GetNativeDevice() { return m_mtl_device; } -protected: +private: id m_mtl_device; }; @@ -50,14 +50,14 @@ public: ~SystemMT() override; void CheckForChanges() override {} - const Devices& UpdateGpuDevices(Device::Feature::Mask supported_features) override; + const Ptrs& UpdateGpuDevices(Device::Feature::Mask supported_features) override; private: void OnDeviceNotification(id mtl_device, MTLDeviceNotificationName device_notification); void NotifyDevice(const id& mtl_device, Device::Notification device_notification); void AddDevice(const id& mtl_device); - const Device::Ptr& FindMetalDevice(const id& mtl_device) const; + const Ptr& FindMetalDevice(const id& mtl_device) const; id m_device_observer = nil; }; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/DeviceMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/DeviceMT.mm index 365093588..bd549a9b8 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/DeviceMT.mm +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/DeviceMT.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ #include "DeviceMT.hh" -#include +#include #include #include @@ -34,12 +34,12 @@ Device::Feature::Mask DeviceMT::GetSupportedFeatures(const id& mtl_device) { ITT_FUNCTION_TASK(); - Device::Feature::Mask supported_featues = Device::Feature::Value::BasicRendering; - return supported_featues; + Device::Feature::Mask supported_features = Device::Feature::Value::BasicRendering; + return supported_features; } DeviceMT::DeviceMT(const id& mtl_device) - : DeviceBase(MacOS::ConvertFromNSType(mtl_device.name), false, + : DeviceBase(MacOS::ConvertFromNsType(mtl_device.name), false, GetSupportedFeatures(mtl_device)) , m_mtl_device(mtl_device) { @@ -69,16 +69,16 @@ } } -const Devices& SystemMT::UpdateGpuDevices(Device::Feature::Mask supported_features) +const Ptrs& SystemMT::UpdateGpuDevices(Device::Feature::Mask supported_features) { ITT_FUNCTION_TASK(); if (m_device_observer != nil) { MTLRemoveDeviceObserver(m_device_observer); } - - m_supported_features = supported_features; - m_devices.clear(); + + SetGpuSupportedFeatures(supported_features); + ClearDevices(); NSArray>* mtl_devices = MTLCopyAllDevicesWithObserver(&m_device_observer, ^(id device, MTLDeviceNotificationName device_notification) @@ -91,7 +91,7 @@ AddDevice(mtl_device); } - return m_devices; + return GetGpuDevices(); } void SystemMT::OnDeviceNotification(id mtl_device, MTLDeviceNotificationName device_notification) @@ -114,7 +114,7 @@ void SystemMT::NotifyDevice(const id& mtl_device, Device::Notification device_notification) { ITT_FUNCTION_TASK(); - const Device::Ptr& sp_device = FindMetalDevice(mtl_device); + const Ptr& sp_device = FindMetalDevice(mtl_device); if (!sp_device) { assert(0); @@ -127,18 +127,18 @@ { ITT_FUNCTION_TASK(); Device::Feature::Mask device_supported_features = DeviceMT::GetSupportedFeatures(mtl_device); - if (!(device_supported_features & m_supported_features)) + if (!(device_supported_features & GetGpuSupportedFeatures())) return; - - Device::Ptr sp_device = std::make_shared(mtl_device); - m_devices.push_back(sp_device); + + SystemBase::AddDevice(std::make_shared(mtl_device)); } -const Device::Ptr& SystemMT::FindMetalDevice(const id& mtl_device) const +const Ptr& SystemMT::FindMetalDevice(const id& mtl_device) const { ITT_FUNCTION_TASK(); - const auto device_it = std::find_if(m_devices.begin(), m_devices.end(), - [mtl_device](const Device::Ptr& sp_device) + const Ptrs& devices = GetGpuDevices(); + const auto device_it = std::find_if(devices.begin(), devices.end(), + [mtl_device](const Ptr& sp_device) { assert(!!sp_device); if (!sp_device) return false; @@ -146,8 +146,8 @@ return metal_device.GetNativeDevice() == mtl_device; }); - static const Device::Ptr sp_empty_device; - return device_it != m_devices.end() ? *device_it : sp_empty_device; + static const Ptr s_sp_empty_device; + return device_it != devices.end() ? *device_it : s_sp_empty_device; } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/FenceMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/FenceMT.hh new file mode 100644 index 000000000..dae1fac13 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/FenceMT.hh @@ -0,0 +1,63 @@ +/****************************************************************************** + +Copyright 2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/FenceMT.hh +Metal fence implementation. + +******************************************************************************/ + +#pragma once + +#include + +#include +#include + +#import + +namespace Methane::Graphics +{ + +class CommandQueueMT; + +class FenceMT final : public FenceBase +{ +public: + FenceMT(CommandQueueBase& command_queue); + ~FenceMT(); + + // Fence overrides + void Signal() override; + void Wait() override; + + // Object override + void SetName(const std::string& name) noexcept override; + +private: + CommandQueueMT& GetCommandQueueMT(); + + static dispatch_queue_t& GetDispatchQueue(); + + id m_mtl_event; + MTLSharedEventListener* m_mtl_event_listener; + std::mutex m_wait_mutex; + std::condition_variable m_wait_condition_var; + bool m_is_signalled = false; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/FenceMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/FenceMT.mm new file mode 100644 index 000000000..c17360927 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/FenceMT.mm @@ -0,0 +1,115 @@ +/****************************************************************************** + +Copyright 2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/FenceMT.mm +Metal fence implementation. + +******************************************************************************/ + +#include "FenceMT.hh" +#include "CommandQueueMT.hh" +#include "DeviceMT.hh" + +#include +#include +#include + +namespace Methane::Graphics +{ + +UniquePtr Fence::Create(CommandQueue& command_queue) +{ + ITT_FUNCTION_TASK(); + return std::make_unique(static_cast(command_queue)); +} + +dispatch_queue_t& FenceMT::GetDispatchQueue() +{ + static dispatch_queue_t s_fences_dispatch_queue = dispatch_queue_create("com.example.methane.fences", NULL); + return s_fences_dispatch_queue; +} + +FenceMT::FenceMT(CommandQueueBase& command_queue) + : FenceBase(command_queue) + , m_mtl_event([GetCommandQueueMT().GetContextMT().GetDeviceMT().GetNativeDevice() newSharedEvent]) + , m_mtl_event_listener([[MTLSharedEventListener alloc] initWithDispatchQueue:GetDispatchQueue()]) +{ + ITT_FUNCTION_TASK(); +} + +FenceMT::~FenceMT() +{ + ITT_FUNCTION_TASK(); + [m_mtl_event_listener release]; +} + +void FenceMT::Signal() +{ + ITT_FUNCTION_TASK(); + + FenceBase::Signal(); + + id mtl_command_buffer = [GetCommandQueueMT().GetNativeCommandQueue() commandBuffer]; + [mtl_command_buffer encodeSignalEvent:m_mtl_event value:GetValue()]; + [mtl_command_buffer commit]; + + m_is_signalled = false; +} + +void FenceMT::Wait() +{ + ITT_FUNCTION_TASK(); + + FenceBase::Wait(); + + assert(m_mtl_event != nil); + assert(m_mtl_event_listener != nil); + uint64_t signalled_value = m_mtl_event.signaledValue; + if (signalled_value >= GetValue()) + return; + + assert(!m_is_signalled); + [m_mtl_event notifyListener:m_mtl_event_listener + atValue:GetValue() + block:^(id, uint64_t /*value*/) + { + m_is_signalled = true; + m_wait_condition_var.notify_one(); + }]; + std::unique_lock lock(m_wait_mutex); + m_wait_condition_var.wait(lock, [this]{ return m_is_signalled; }); +} + +void FenceMT::SetName(const std::string& name) noexcept +{ + ITT_FUNCTION_TASK(); + if (ObjectBase::GetName() == name) + return; + + ObjectBase::SetName(name); + + m_mtl_event.label = MacOS::ConvertToNsType(name); +} + +CommandQueueMT& FenceMT::GetCommandQueueMT() +{ + ITT_FUNCTION_TASK(); + return static_cast(GetCommandQueue()); +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ParallelRenderCommandListMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ParallelRenderCommandListMT.hh index eb7767762..f7e5ee49e 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ParallelRenderCommandListMT.hh +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ParallelRenderCommandListMT.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -39,15 +39,13 @@ class RenderPassMT; class ParallelRenderCommandListMT final : public ParallelRenderCommandListBase { public: - using Ptr = std::shared_ptr; - ParallelRenderCommandListMT(CommandQueueBase& command_queue, RenderPassBase& render_pass); // ParallelRenderCommandList interface - void Reset(const RenderState::Ptr& sp_render_state, const std::string& debug_group = "") override; + void Reset(const Ptr& sp_render_state, const std::string& debug_group = "") override; // CommandList interface - void Commit(bool present_drawable) override; + void Commit() override; // CommandListBase interface void Execute(uint32_t frame_index) override; @@ -58,7 +56,7 @@ public: id& GetNativeCommandBuffer() noexcept { return m_mtl_cmd_buffer; } id& GetNativeParallelRenderEncoder() noexcept { return m_mtl_parallel_render_encoder; } -protected: +private: CommandQueueMT& GetCommandQueueMT() noexcept; RenderPassMT& GetPassMT(); diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ParallelRenderCommandListMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ParallelRenderCommandListMT.mm index 5a1c4f935..c6e3fe1c2 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ParallelRenderCommandListMT.mm +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ParallelRenderCommandListMT.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,16 +23,17 @@ #include "ParallelRenderCommandListMT.hh" #include "RenderPassMT.hh" +#include "RenderStateMT.hh" #include "CommandQueueMT.hh" -#include "ContextMT.hh" +#include "RenderContextMT.hh" -#include +#include #include namespace Methane::Graphics { -ParallelRenderCommandList::Ptr ParallelRenderCommandList::Create(CommandQueue& command_queue, RenderPass& render_pass) +Ptr ParallelRenderCommandList::Create(CommandQueue& command_queue, RenderPass& render_pass) { ITT_FUNCTION_TASK(); return std::make_shared(static_cast(command_queue), static_cast(render_pass)); @@ -50,7 +51,7 @@ ParallelRenderCommandListBase::SetName(name); - NSString* ns_name = MacOS::ConvertToNSType(name); + NSString* ns_name = MacOS::ConvertToNsType(name); if (m_mtl_parallel_render_encoder != nil) { @@ -63,7 +64,7 @@ } } -void ParallelRenderCommandListMT::Reset(const RenderState::Ptr& sp_render_state, const std::string& debug_group) +void ParallelRenderCommandListMT::Reset(const Ptr& sp_render_state, const std::string& debug_group) { ITT_FUNCTION_TASK(); if (m_mtl_parallel_render_encoder != nil) @@ -80,36 +81,36 @@ m_mtl_cmd_buffer = [GetCommandQueueMT().GetNativeCommandQueue() commandBuffer]; assert(m_mtl_cmd_buffer != nil); - m_mtl_cmd_buffer.label = MacOS::ConvertToNSType(GetName()); + m_mtl_cmd_buffer.label = MacOS::ConvertToNsType(GetName()); } - assert(!!mtl_render_pass); + assert(mtl_render_pass != nil); m_mtl_parallel_render_encoder = [m_mtl_cmd_buffer parallelRenderCommandEncoderWithDescriptor: mtl_render_pass]; assert(m_mtl_parallel_render_encoder != nil); - m_mtl_parallel_render_encoder.label = MacOS::ConvertToNSType(GetName()); + m_mtl_parallel_render_encoder.label = MacOS::ConvertToNsType(GetName()); + + if (sp_render_state) + { + static_cast(*sp_render_state).InitializeNativeStates(); + } ParallelRenderCommandListBase::Reset(sp_render_state, debug_group); } -void ParallelRenderCommandListMT::Commit(bool present_drawable) +void ParallelRenderCommandListMT::Commit() { ITT_FUNCTION_TASK(); assert(!IsCommitted()); - ParallelRenderCommandListBase::Commit(present_drawable); + ParallelRenderCommandListBase::Commit(); if (!m_mtl_cmd_buffer || !m_mtl_parallel_render_encoder) return; [m_mtl_parallel_render_encoder endEncoding]; m_mtl_parallel_render_encoder = nil; - - if (present_drawable) - { - [m_mtl_cmd_buffer presentDrawable: GetCommandQueueMT().GetContextMT().GetNativeDrawable()]; - } [m_mtl_cmd_buffer enqueue]; } @@ -131,7 +132,7 @@ CommandQueueMT& ParallelRenderCommandListMT::GetCommandQueueMT() noexcept { ITT_FUNCTION_TASK(); - return static_cast(*m_sp_command_queue); + return static_cast(GetCommandQueue()); } RenderPassMT& ParallelRenderCommandListMT::GetPassMT() diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramBindingsMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramBindingsMT.hh new file mode 100644 index 000000000..28ae96d2c --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramBindingsMT.hh @@ -0,0 +1,74 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/ProgramBindingsMT.hh +Metal implementation of the program bindings interface. + +******************************************************************************/ + +#pragma once + +#include + +#import + +namespace Methane::Graphics +{ + +class ProgramBindingsMT final : public ProgramBindingsBase +{ +public: + class ArgumentBindingMT final : public ArgumentBindingBase + { + public: + struct SettingsMT final : Settings + { + uint32_t argument_index; + }; + + ArgumentBindingMT(const ContextBase& context, SettingsMT settings); + ArgumentBindingMT(const ArgumentBindingMT& other) = default; + + // ArgumentBinding interface + void SetResourceLocations(const Resource::Locations& resource_locations) override; + + const SettingsMT& GetSettingsMT() const noexcept { return m_settings_mt; } + const std::vector>& GetNativeSamplerStates() const { return m_mtl_sampler_states; } + const std::vector>& GetNativeTextures() const { return m_mtl_textures; } + const std::vector>& GetNativeBuffers() const { return m_mtl_buffers; } + const std::vector& GetBufferOffsets() const { return m_mtl_buffer_offsets; } + + private: + const SettingsMT m_settings_mt; + std::vector> m_mtl_sampler_states; + std::vector> m_mtl_textures; + std::vector> m_mtl_buffers; + std::vector m_mtl_buffer_offsets; + }; + + ProgramBindingsMT(const Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument); + ProgramBindingsMT(const ProgramBindingsMT& other_program_bindings, const ResourceLocationsByArgument& replace_resource_location_by_argument); + + // ProgramBindings interface + void Apply(CommandListBase& command_list, ApplyBehavior::Mask apply_behavior) const override; + + // ProgramBindingsBase interface + void CompleteInitialization() override { } +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramBindingsMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramBindingsMT.mm new file mode 100644 index 000000000..8a1307732 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramBindingsMT.mm @@ -0,0 +1,270 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/ProgramBindingsMT.mm +Metal implementation of the program bindings interface. + +******************************************************************************/ + +#include "ProgramBindingsMT.hh" +#include "BufferMT.hh" +#include "TextureMT.hh" +#include "SamplerMT.hh" +#include "RenderCommandListMT.hh" + +#include + +namespace Methane::Graphics +{ + +template +static void SetMetalResource(Shader::Type shader_type, id& mtl_cmd_encoder, const TMetalResource& mtl_buffer, uint32_t arg_index, Data::Size buffer_offset) noexcept; + +template +static void SetMetalResources(Shader::Type shader_type, id& mtl_cmd_encoder, const std::vector& mtl_buffer, uint32_t arg_index, const std::vector& buffer_offsets) noexcept; + +template<> +void SetMetalResource(Shader::Type shader_type, id& mtl_cmd_encoder, const id& mtl_buffer, uint32_t arg_index, Data::Size buffer_offset) noexcept +{ + ITT_FUNCTION_TASK(); + switch(shader_type) + { + case Shader::Type::Vertex: [mtl_cmd_encoder setVertexBuffer:mtl_buffer offset:buffer_offset atIndex:arg_index]; break; + case Shader::Type::Pixel: [mtl_cmd_encoder setFragmentBuffer:mtl_buffer offset:buffer_offset atIndex:arg_index]; break; + default: assert(0); + } +} + +template<> +void SetMetalResources(Shader::Type shader_type, id& mtl_cmd_encoder, const std::vector>& mtl_buffers, + uint32_t arg_index, const std::vector& buffer_offsets) noexcept +{ + ITT_FUNCTION_TASK(); + const NSRange args_range = NSMakeRange(arg_index, mtl_buffers.size()); + switch(shader_type) + { + case Shader::Type::Vertex: [mtl_cmd_encoder setVertexBuffers:mtl_buffers.data() offsets:buffer_offsets.data() withRange:args_range]; break; + case Shader::Type::Pixel: [mtl_cmd_encoder setFragmentBuffers:mtl_buffers.data() offsets:buffer_offsets.data() withRange:args_range]; break; + default: assert(0); + } +} + +template<> +void SetMetalResource(Shader::Type shader_type, id& mtl_cmd_encoder, const id& mtl_texture, uint32_t arg_index, Data::Size) noexcept +{ + ITT_FUNCTION_TASK(); + switch(shader_type) + { + case Shader::Type::Vertex: [mtl_cmd_encoder setVertexTexture:mtl_texture atIndex:arg_index]; break; + case Shader::Type::Pixel: [mtl_cmd_encoder setFragmentTexture:mtl_texture atIndex:arg_index]; break; + default: assert(0); + } +} + +template<> +void SetMetalResources(Shader::Type shader_type, id& mtl_cmd_encoder, const std::vector>& mtl_textures, + uint32_t arg_index, const std::vector&) noexcept +{ + ITT_FUNCTION_TASK(); + const NSRange args_range = NSMakeRange(arg_index, mtl_textures.size()); + switch(shader_type) + { + case Shader::Type::Vertex: [mtl_cmd_encoder setVertexTextures:mtl_textures.data() withRange:args_range]; break; + case Shader::Type::Pixel: [mtl_cmd_encoder setFragmentTextures:mtl_textures.data() withRange:args_range]; break; + default: assert(0); + } +} + +template<> +void SetMetalResource(Shader::Type shader_type, id& mtl_cmd_encoder, const id& mtl_sampler, uint32_t arg_index, Data::Size) noexcept +{ + ITT_FUNCTION_TASK(); + switch(shader_type) + { + case Shader::Type::Vertex: [mtl_cmd_encoder setVertexSamplerState:mtl_sampler atIndex:arg_index]; break; + case Shader::Type::Pixel: [mtl_cmd_encoder setFragmentSamplerState:mtl_sampler atIndex:arg_index]; break; + default: assert(0); + } +} + +template<> +void SetMetalResources(Shader::Type shader_type, id& mtl_cmd_encoder, const std::vector>& mtl_samplers, + uint32_t arg_index, const std::vector&) noexcept +{ + ITT_FUNCTION_TASK(); + const NSRange args_range = NSMakeRange(arg_index, mtl_samplers.size()); + switch(shader_type) + { + case Shader::Type::Vertex: [mtl_cmd_encoder setVertexSamplerStates:mtl_samplers.data() withRange:args_range]; break; + case Shader::Type::Pixel: [mtl_cmd_encoder setFragmentSamplerStates:mtl_samplers.data() withRange:args_range]; break; + default: assert(0); + } +} + +template +static void SetMetalResourcesForAll(Shader::Type shader_type, const Program& program, id& mtl_cmd_encoder, + const std::vector& mtl_resources, uint32_t arg_index, + const std::vector& offsets = std::vector()) noexcept +{ + ITT_FUNCTION_TASK(); + assert(!mtl_resources.empty()); + + if (shader_type == Shader::Type::All) + { + if (mtl_resources.size() > 1) + { + for (Shader::Type specific_shader_type : program.GetShaderTypes()) + { + SetMetalResources(specific_shader_type, mtl_cmd_encoder, mtl_resources, arg_index, offsets); + } + } + else + { + for (Shader::Type specific_shader_type : program.GetShaderTypes()) + { + SetMetalResource(specific_shader_type, mtl_cmd_encoder, mtl_resources.back(), arg_index, + offsets.empty() ? 0 : offsets.back()); + } + } + } + else + { + if (mtl_resources.size() > 1) + { + SetMetalResources(shader_type, mtl_cmd_encoder, mtl_resources, arg_index, offsets); + } + else + { + SetMetalResource(shader_type, mtl_cmd_encoder, mtl_resources.back(), arg_index, + offsets.empty() ? 0 : offsets.back()); + } + } +} + +Ptr ProgramBindings::Create(const Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument) +{ + ITT_FUNCTION_TASK(); + return std::make_shared(sp_program, resource_locations_by_argument); +} + +Ptr ProgramBindings::CreateCopy(const ProgramBindings& other_program_bindings, const ResourceLocationsByArgument& replace_resource_locations_by_argument) +{ + ITT_FUNCTION_TASK(); + return std::make_shared(static_cast(other_program_bindings), replace_resource_locations_by_argument); +} + +Ptr ProgramBindingsBase::ArgumentBindingBase::CreateCopy(const ArgumentBindingBase& other_argument_binding) +{ + ITT_FUNCTION_TASK(); + return std::make_shared(static_cast(other_argument_binding)); +} + +ProgramBindingsMT::ArgumentBindingMT::ArgumentBindingMT(const ContextBase& context, SettingsMT settings) + : ArgumentBindingBase(context, settings) + , m_settings_mt(std::move(settings)) +{ + ITT_FUNCTION_TASK(); +} + +void ProgramBindingsMT::ArgumentBindingMT::SetResourceLocations(const Resource::Locations& resource_locations) +{ + ITT_FUNCTION_TASK(); + ArgumentBindingBase::SetResourceLocations(resource_locations); + + m_mtl_sampler_states.clear(); + m_mtl_textures.clear(); + m_mtl_buffers.clear(); + m_mtl_buffer_offsets.clear(); + + switch(m_settings_mt.resource_type) + { + case Resource::Type::Sampler: + m_mtl_sampler_states.reserve(resource_locations.size()); + std::transform(resource_locations.begin(), resource_locations.end(), std::back_inserter(m_mtl_sampler_states), + [](const Resource::Location& resource_location) + { return dynamic_cast(resource_location.GetResource()).GetNativeSamplerState(); }); + break; + + case Resource::Type::Texture: + m_mtl_textures.reserve(resource_locations.size()); + std::transform(resource_locations.begin(), resource_locations.end(), std::back_inserter(m_mtl_textures), + [](const Resource::Location& resource_location) + { return dynamic_cast(resource_location.GetResource()).GetNativeTexture(); }); + break; + + case Resource::Type::Buffer: + m_mtl_buffers.reserve(resource_locations.size()); + m_mtl_buffer_offsets.reserve(resource_locations.size()); + for (const Resource::Location& resource_location : resource_locations) + { + m_mtl_buffers.push_back(dynamic_cast(resource_location.GetResource()).GetNativeBuffer()); + m_mtl_buffer_offsets.push_back(static_cast(resource_location.GetOffset())); + } + break; + } +} + +ProgramBindingsMT::ProgramBindingsMT(const Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument) + : ProgramBindingsBase(sp_program, resource_locations_by_argument) +{ + ITT_FUNCTION_TASK(); +} + +ProgramBindingsMT::ProgramBindingsMT(const ProgramBindingsMT& other_program_bindings, const ResourceLocationsByArgument& replace_resource_locations_by_argument) + : ProgramBindingsBase(other_program_bindings, replace_resource_locations_by_argument) +{ + ITT_FUNCTION_TASK(); +} + +void ProgramBindingsMT::Apply(CommandListBase& command_list, ApplyBehavior::Mask apply_behavior) const +{ + ITT_FUNCTION_TASK(); + + RenderCommandListMT& metal_command_list = static_cast(command_list); + id& mtl_cmd_encoder = metal_command_list.GetNativeRenderEncoder(); + + for(const auto& binding_by_argument : GetArgumentBindings()) + { + const Program::Argument& program_argument = binding_by_argument.first; + const ArgumentBindingMT& metal_argument_binding = static_cast(*binding_by_argument.second); + + if ((apply_behavior & ApplyBehavior::ConstantOnce || apply_behavior & ApplyBehavior::ChangesOnly) && metal_command_list.GetProgramBindings() && + metal_argument_binding.IsAlreadyApplied(GetProgram(), *metal_command_list.GetProgramBindings(), apply_behavior & ApplyBehavior::ChangesOnly)) + continue; + + const uint32_t arg_index = metal_argument_binding.GetSettingsMT().argument_index; + + switch(metal_argument_binding.GetSettingsMT().resource_type) + { + case Resource::Type::Buffer: + SetMetalResourcesForAll(program_argument.shader_type, GetProgram(), mtl_cmd_encoder, metal_argument_binding.GetNativeBuffers(), arg_index, + metal_argument_binding.GetBufferOffsets()); + break; + + case Resource::Type::Texture: + SetMetalResourcesForAll(program_argument.shader_type, GetProgram(), mtl_cmd_encoder, metal_argument_binding.GetNativeTextures(), arg_index); + break; + + case Resource::Type::Sampler: + SetMetalResourcesForAll(program_argument.shader_type, GetProgram(), mtl_cmd_encoder, metal_argument_binding.GetNativeSamplerStates(), arg_index); + break; + } + } +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramLibraryMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramLibraryMT.hh new file mode 100644 index 000000000..5df25759e --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramLibraryMT.hh @@ -0,0 +1,48 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/ProgramLibraryMT.hh +Wrapper of the Metal program library. + +******************************************************************************/ + +#pragma once + +#import + +#include + +namespace Methane::Graphics +{ + +class DeviceMT; + +class ProgramLibraryMT final +{ +public: + ProgramLibraryMT(DeviceMT& metal_device, const std::string& library_name = ""); + ~ProgramLibraryMT(); + + id& Get() noexcept { return m_mtl_library; } + +private: + NSError* m_ns_error = nil; + id m_mtl_library; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramLibraryMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramLibraryMT.mm new file mode 100644 index 000000000..d9f085fc3 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramLibraryMT.mm @@ -0,0 +1,58 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/ProgramLibraryMT.mm +Wrapper of the Metal program library. + +******************************************************************************/ + +#include "ProgramLibraryMT.hh" +#include "DeviceMT.hh" + +#include +#include +#include + +namespace Methane::Graphics +{ + +static NSString* GetLibraryFullPath(const std::string& library_name) +{ + return MacOS::ConvertToNsType(Platform::GetResourceDir() + "/" + library_name + ".metallib"); +} + +ProgramLibraryMT::ProgramLibraryMT(DeviceMT& metal_device, const std::string& library_name) + : m_mtl_library(library_name.empty() + ? [metal_device.GetNativeDevice() newDefaultLibrary] + : [metal_device.GetNativeDevice() newLibraryWithFile:GetLibraryFullPath(library_name) error:&m_ns_error]) +{ + ITT_FUNCTION_TASK(); + if (!m_mtl_library) + { + const std::string error_msg = MacOS::ConvertFromNsType([m_ns_error localizedDescription]); + throw std::runtime_error("Failed to create " + (library_name.empty() ? std::string("default") : library_name) + " Metal library: " + error_msg); + } +} + +ProgramLibraryMT::~ProgramLibraryMT() +{ + ITT_FUNCTION_TASK(); + [m_mtl_library release]; +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramMT.hh index 58cb4506a..7008e2aa1 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramMT.hh +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramMT.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,25 +30,12 @@ Metal implementation of the program interface. namespace Methane::Graphics { -class ContextMT; +struct IContextMT; class ShaderMT; -class ProgramMT : public ProgramBase +class ProgramMT final : public ProgramBase { public: - class ResourceBindingsMT : public ResourceBindingsBase - { - public: - ResourceBindingsMT(const Program::Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument); - ResourceBindingsMT(const ResourceBindingsMT& other_resource_bindings, const ResourceLocationsByArgument& replace_resource_location_by_argument); - - // ResourceBindings interface - void Apply(CommandList& command_list, ApplyBehavior::Mask apply_behavior) const override; - - // ResourceBindingsBase interface - void CompleteInitialization() override { } - }; - ProgramMT(ContextBase& context, const Settings& settings); ~ProgramMT() override; @@ -57,8 +44,8 @@ public: id GetNativeShaderFunction(Shader::Type shader_type) noexcept; MTLVertexDescriptor* GetNativeVertexDescriptor() noexcept { return m_mtl_vertex_desc; } -protected: - ContextMT& GetContextMT() noexcept; +private: + IContextMT& GetContextMT() noexcept; void SetNativeShaderArguments(Shader::Type shader_type, NSArray* mtl_arguments) noexcept; MTLVertexDescriptor* m_mtl_vertex_desc = nil; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramMT.mm index 94135026e..ac482c478 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramMT.mm +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ProgramMT.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,218 +23,21 @@ #include "ProgramMT.hh" #include "ShaderMT.hh" -#include "BufferMT.hh" -#include "TextureMT.hh" -#include "SamplerMT.hh" -#include "ContextMT.hh" +#include "ContextMT.h" #include "DeviceMT.hh" -#include "RenderCommandListMT.hh" #include "TypesMT.hh" -#include +#include #include - -#include +#include namespace Methane::Graphics { -template -static void SetMetalResource(Shader::Type shader_type, id& mtl_cmd_encoder, const TMetalResource& mtl_buffer, uint32_t arg_index, Data::Size buffer_offset) noexcept; - -template -static void SetMetalResources(Shader::Type shader_type, id& mtl_cmd_encoder, const std::vector& mtl_buffer, uint32_t arg_index, const std::vector& buffer_offsets) noexcept; - -template<> -void SetMetalResource(Shader::Type shader_type, id& mtl_cmd_encoder, const id& mtl_buffer, uint32_t arg_index, Data::Size buffer_offset) noexcept -{ - ITT_FUNCTION_TASK(); - switch(shader_type) - { - case Shader::Type::Vertex: [mtl_cmd_encoder setVertexBuffer:mtl_buffer offset:buffer_offset atIndex:arg_index]; break; - case Shader::Type::Pixel: [mtl_cmd_encoder setFragmentBuffer:mtl_buffer offset:buffer_offset atIndex:arg_index]; break; - default: assert(0); - } -} - -template<> -void SetMetalResources(Shader::Type shader_type, id& mtl_cmd_encoder, const std::vector>& mtl_buffers, - uint32_t arg_index, const std::vector& buffer_offsets) noexcept -{ - ITT_FUNCTION_TASK(); - const NSRange args_range = NSMakeRange(arg_index, mtl_buffers.size()); - switch(shader_type) - { - case Shader::Type::Vertex: [mtl_cmd_encoder setVertexBuffers:mtl_buffers.data() offsets:buffer_offsets.data() withRange:args_range]; break; - case Shader::Type::Pixel: [mtl_cmd_encoder setFragmentBuffers:mtl_buffers.data() offsets:buffer_offsets.data() withRange:args_range]; break; - default: assert(0); - } -} - -template<> -void SetMetalResource(Shader::Type shader_type, id& mtl_cmd_encoder, const id& mtl_texture, uint32_t arg_index, Data::Size) noexcept -{ - ITT_FUNCTION_TASK(); - switch(shader_type) - { - case Shader::Type::Vertex: [mtl_cmd_encoder setVertexTexture:mtl_texture atIndex:arg_index]; break; - case Shader::Type::Pixel: [mtl_cmd_encoder setFragmentTexture:mtl_texture atIndex:arg_index]; break; - default: assert(0); - } -} - -template<> -void SetMetalResources(Shader::Type shader_type, id& mtl_cmd_encoder, const std::vector>& mtl_textures, - uint32_t arg_index, const std::vector&) noexcept -{ - ITT_FUNCTION_TASK(); - const NSRange args_range = NSMakeRange(arg_index, mtl_textures.size()); - switch(shader_type) - { - case Shader::Type::Vertex: [mtl_cmd_encoder setVertexTextures:mtl_textures.data() withRange:args_range]; break; - case Shader::Type::Pixel: [mtl_cmd_encoder setFragmentTextures:mtl_textures.data() withRange:args_range]; break; - default: assert(0); - } -} - -template<> -void SetMetalResource(Shader::Type shader_type, id& mtl_cmd_encoder, const id& mtl_sampler, uint32_t arg_index, Data::Size) noexcept -{ - ITT_FUNCTION_TASK(); - switch(shader_type) - { - case Shader::Type::Vertex: [mtl_cmd_encoder setVertexSamplerState:mtl_sampler atIndex:arg_index]; break; - case Shader::Type::Pixel: [mtl_cmd_encoder setFragmentSamplerState:mtl_sampler atIndex:arg_index]; break; - default: assert(0); - } -} - -template<> -void SetMetalResources(Shader::Type shader_type, id& mtl_cmd_encoder, const std::vector>& mtl_samplers, - uint32_t arg_index, const std::vector&) noexcept -{ - ITT_FUNCTION_TASK(); - const NSRange args_range = NSMakeRange(arg_index, mtl_samplers.size()); - switch(shader_type) - { - case Shader::Type::Vertex: [mtl_cmd_encoder setVertexSamplerStates:mtl_samplers.data() withRange:args_range]; break; - case Shader::Type::Pixel: [mtl_cmd_encoder setFragmentSamplerStates:mtl_samplers.data() withRange:args_range]; break; - default: assert(0); - } -} - -template -static void SetMetalResourcesForAll(Shader::Type shader_type, Program& program, id& mtl_cmd_encoder, - const std::vector& mtl_resources, uint32_t arg_index, - const std::vector& offsets = std::vector()) noexcept -{ - ITT_FUNCTION_TASK(); - assert(!mtl_resources.empty()); - - if (shader_type == Shader::Type::All) - { - if (mtl_resources.size() > 1) - { - for (Shader::Type specific_shader_type : program.GetShaderTypes()) - { - SetMetalResources(specific_shader_type, mtl_cmd_encoder, mtl_resources, arg_index, offsets); - } - } - else - { - for (Shader::Type specific_shader_type : program.GetShaderTypes()) - { - SetMetalResource(specific_shader_type, mtl_cmd_encoder, mtl_resources.back(), arg_index, - offsets.empty() ? 0 : offsets.back()); - } - } - } - else - { - if (mtl_resources.size() > 1) - { - SetMetalResources(shader_type, mtl_cmd_encoder, mtl_resources, arg_index, offsets); - } - else - { - SetMetalResource(shader_type, mtl_cmd_encoder, mtl_resources.back(), arg_index, - offsets.empty() ? 0 : offsets.back()); - } - } -} - -template -static void GetBoundMetalResources(const Resource::Locations& resource_locations, std::vector& out_mtl_resources, std::vector& out_offsets) -{ -} - -Program::ResourceBindings::Ptr Program::ResourceBindings::Create(const Program::Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument) -{ - ITT_FUNCTION_TASK(); - return std::make_shared(sp_program, resource_locations_by_argument); -} - -Program::ResourceBindings::Ptr Program::ResourceBindings::CreateCopy(const ResourceBindings& other_resource_bingings, const ResourceLocationsByArgument& replace_resource_locations_by_argument) -{ - ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(other_resource_bingings), replace_resource_locations_by_argument); -} - -ProgramMT::ResourceBindingsMT::ResourceBindingsMT(const Program::Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument) - : ResourceBindingsBase(sp_program, resource_locations_by_argument) +Ptr Program::Create(Context& context, const Settings& settings) { ITT_FUNCTION_TASK(); -} - -ProgramMT::ResourceBindingsMT::ResourceBindingsMT(const ResourceBindingsMT& other_resource_bindings, const ResourceLocationsByArgument& replace_resource_locations_by_argument) - : ResourceBindingsBase(other_resource_bindings, replace_resource_locations_by_argument) -{ - ITT_FUNCTION_TASK(); -} - -void ProgramMT::ResourceBindingsMT::Apply(CommandList& command_list, ApplyBehavior::Mask apply_behavior) const -{ - ITT_FUNCTION_TASK(); - - RenderCommandListMT& metal_command_list = dynamic_cast(command_list); - const CommandListBase::CommandState& command_state = metal_command_list.GetCommandState(); - id& mtl_cmd_encoder = metal_command_list.GetNativeRenderEncoder(); - - for(const auto& resource_binding_by_argument : m_resource_binding_by_argument) - { - const Argument& program_argument = resource_binding_by_argument.first; - const ShaderMT::ResourceBindingMT& metal_resource_binding = static_cast(*resource_binding_by_argument.second); - - if ((apply_behavior & ApplyBehavior::ConstantOnce || apply_behavior & ApplyBehavior::ChangesOnly) && - metal_resource_binding.IsAlreadyApplied(*m_sp_program, program_argument, command_state, apply_behavior & ApplyBehavior::ChangesOnly)) - continue; - - const uint32_t arg_index = metal_resource_binding.GetSettings().argument_index; - - switch(metal_resource_binding.GetSettings().base.resource_type) - { - case Resource::Type::Buffer: - SetMetalResourcesForAll(program_argument.shader_type, *m_sp_program, mtl_cmd_encoder, metal_resource_binding.GetNativeBuffers(), arg_index, - metal_resource_binding.GetBufferOffsets()); - break; - - case Resource::Type::Texture: - SetMetalResourcesForAll(program_argument.shader_type, *m_sp_program, mtl_cmd_encoder, metal_resource_binding.GetNativeTextures(), arg_index); - break; - - case Resource::Type::Sampler: - SetMetalResourcesForAll(program_argument.shader_type, *m_sp_program, mtl_cmd_encoder, metal_resource_binding.GetNativeSamplerStates(), arg_index); - break; - - default: assert(0); - } - } -} - -Program::Ptr Program::Create(Context& context, const Settings& settings) -{ - ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context), settings); + return std::make_shared(dynamic_cast(context), settings); } ProgramMT::ProgramMT(ContextBase& context, const Settings& settings) @@ -243,14 +46,6 @@ static void GetBoundMetalResources(const Resource::Locations& resource_locations { ITT_FUNCTION_TASK(); - // In case if RT pixel formats are not set, we assume it renders to frame buffer - // NOTE: even when program has no pixel shaders render, render state must have at least one color format to be valid - std::vector color_formats = settings.color_formats; - if (color_formats.empty()) - { - color_formats.push_back(context.GetSettings().color_format); - } - // Create dummy pipeline state to get program reflection of vertex and fragment shader arguments MTLRenderPipelineDescriptor* mtl_reflection_state_desc = [MTLRenderPipelineDescriptor new]; mtl_reflection_state_desc.vertexDescriptor = m_mtl_vertex_desc; @@ -258,22 +53,27 @@ static void GetBoundMetalResources(const Resource::Locations& resource_locations mtl_reflection_state_desc.fragmentFunction = GetNativeShaderFunction(Shader::Type::Pixel); // Fill state color attachment descriptors matching program's pixel shader output + // NOTE: even when program has no pixel shaders render, render state must have at least one color format to be valid uint32_t attachment_index = 0; - for(PixelFormat color_format : color_formats) + for(PixelFormat color_format : settings.color_formats) { mtl_reflection_state_desc.colorAttachments[attachment_index++].pixelFormat = TypeConverterMT::DataFormatToMetalPixelType(color_format); } mtl_reflection_state_desc.colorAttachments[attachment_index].pixelFormat = MTLPixelFormatInvalid; - mtl_reflection_state_desc.depthAttachmentPixelFormat = TypeConverterMT::DataFormatToMetalPixelType(m_settings.depth_format); + mtl_reflection_state_desc.depthAttachmentPixelFormat = TypeConverterMT::DataFormatToMetalPixelType(ProgramBase::GetSettings().depth_format); - ContextMT& metal_context = static_cast(context); + IContextMT& metal_context = dynamic_cast(context); NSError* ns_error = nil; - m_mtl_dummy_pipeline_state_for_reflection = [metal_context.GetDeviceMT().GetNativeDevice() newRenderPipelineStateWithDescriptor:mtl_reflection_state_desc options:MTLPipelineOptionArgumentInfo reflection:&m_mtl_render_pipeline_reflection error:&ns_error]; + id& mtl_device = metal_context.GetDeviceMT().GetNativeDevice(); + m_mtl_dummy_pipeline_state_for_reflection = [mtl_device newRenderPipelineStateWithDescriptor:mtl_reflection_state_desc + options:MTLPipelineOptionArgumentInfo + reflection:&m_mtl_render_pipeline_reflection + error:&ns_error]; if (ns_error != nil) { - const std::string error_msg = MacOS::ConvertFromNSType([ns_error localizedDescription]); + const std::string error_msg = MacOS::ConvertFromNsType([ns_error localizedDescription]); throw std::runtime_error("Failed to create dummy pipeline state for program reflection: " + error_msg); } @@ -281,7 +81,7 @@ static void GetBoundMetalResources(const Resource::Locations& resource_locations { SetNativeShaderArguments(Shader::Type::Vertex, m_mtl_render_pipeline_reflection.vertexArguments); SetNativeShaderArguments(Shader::Type::Pixel, m_mtl_render_pipeline_reflection.fragmentArguments); - InitResourceBindings(settings.constant_argument_names, settings.addressable_argument_names); + InitArgumentBindings(settings.argument_descriptions); } } @@ -292,10 +92,10 @@ static void GetBoundMetalResources(const Resource::Locations& resource_locations [m_mtl_vertex_desc release]; } -ContextMT& ProgramMT::GetContextMT() noexcept +IContextMT& ProgramMT::GetContextMT() noexcept { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(GetContext()); } ShaderMT& ProgramMT::GetShaderMT(Shader::Type shader_type) noexcept diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderCommandListMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderCommandListMT.hh index 19890f9f0..b3878b472 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderCommandListMT.hh +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderCommandListMT.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,8 +25,6 @@ Metal implementation of the render command list interface. #include -#include - #import namespace Methane::Graphics @@ -45,15 +43,15 @@ public: // CommandList interface void PushDebugGroup(const std::string& name) override; void PopDebugGroup() override; - void Commit(bool present_drawable) override; + void Commit() override; // CommandListBase interface void SetResourceBarriers(const ResourceBase::Barriers&) override { } void Execute(uint32_t frame_index) override; // RenderCommandList interface - void Reset(const RenderState::Ptr& sp_render_state, const std::string& debug_group = "") override; - void SetVertexBuffers(const Buffer::Refs& vertex_buffers) override; + void Reset(const Ptr& sp_render_state, const std::string& debug_group = "") override; + void SetVertexBuffers(const Refs& vertex_buffers) override; void DrawIndexed(Primitive primitive, Buffer& index_buffer, uint32_t index_count, uint32_t start_index, uint32_t start_vertex, uint32_t instance_count, uint32_t start_instance) override; @@ -63,27 +61,15 @@ public: // Object interface void SetName(const std::string& label) override; - bool IsRenderEncoding() const { return m_mtl_render_encoder != nil; } - void StartRenderEncoding(); - void EndRenderEncoding(); - - bool IsBlitEncoding() const { return m_mtl_blit_encoder != nil; } - void StartBlitEncoding(); - void EndBlitEncoding(); - id& GetNativeCommandBuffer() noexcept { return m_mtl_cmd_buffer; } id& GetNativeRenderEncoder() noexcept { return m_mtl_render_encoder; } - id& GetNativeBlitEncoder() noexcept { return m_mtl_blit_encoder; } -protected: - void InitializeCommandBuffer(); - +private: CommandQueueMT& GetCommandQueueMT() noexcept; - RenderPassMT& GetPassMT(); + RenderPassMT& GetRenderPassMT(); id m_mtl_cmd_buffer = nil; id m_mtl_render_encoder = nil; - id m_mtl_blit_encoder = nil; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderCommandListMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderCommandListMT.mm index 35da0a1e0..c76ec1c07 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderCommandListMT.mm +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderCommandListMT.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,10 +26,10 @@ #include "RenderStateMT.hh" #include "RenderPassMT.hh" #include "CommandQueueMT.hh" -#include "ContextMT.hh" +#include "RenderContextMT.hh" #include "BufferMT.hh" -#include +#include #include namespace Methane::Graphics @@ -46,18 +46,17 @@ static MTLPrimitiveType PrimitiveTypeToMetal(RenderCommandList::Primitive primit case RenderCommandList::Primitive::LineStrip: return MTLPrimitiveTypeLineStrip; case RenderCommandList::Primitive::Triangle: return MTLPrimitiveTypeTriangle; case RenderCommandList::Primitive::TriangleStrip: return MTLPrimitiveTypeTriangleStrip; - default: assert(0); } return MTLPrimitiveTypeTriangleStrip; } -RenderCommandList::Ptr RenderCommandList::Create(CommandQueue& command_queue, RenderPass& render_pass) +Ptr RenderCommandList::Create(CommandQueue& command_queue, RenderPass& render_pass) { ITT_FUNCTION_TASK(); return std::make_shared(static_cast(command_queue), static_cast(render_pass)); } -RenderCommandList::Ptr RenderCommandList::Create(ParallelRenderCommandList& parallel_render_command_list) +Ptr RenderCommandList::Create(ParallelRenderCommandList& parallel_render_command_list) { ITT_FUNCTION_TASK(); return std::make_shared(static_cast(parallel_render_command_list)); @@ -75,13 +74,45 @@ static MTLPrimitiveType PrimitiveTypeToMetal(RenderCommandList::Primitive primit ITT_FUNCTION_TASK(); } -void RenderCommandListMT::Reset(const RenderState::Ptr& sp_render_state, const std::string& debug_group) +void RenderCommandListMT::Reset(const Ptr& sp_render_state, const std::string& debug_group) { ITT_FUNCTION_TASK(); - RenderCommandListBase::ResetDrawState(); + RenderCommandListBase::ResetCommandState(); - StartRenderEncoding(); + if (m_mtl_render_encoder) + { + RenderCommandListBase::Reset(sp_render_state, debug_group); + return; + } + + if (IsParallel()) + { + Ptr sp_parallel_render_cmd_list = std::static_pointer_cast(GetParallelRenderCommandList()); + assert(!!sp_parallel_render_cmd_list); + id & mtl_parallel_render_command_encoder = sp_parallel_render_cmd_list->GetNativeParallelRenderEncoder(); + m_mtl_render_encoder = [mtl_parallel_render_command_encoder renderCommandEncoder]; + } + else + { + // If command buffer was not created for current frame yet, + // then render pass descriptor should be reset with new frame drawable + MTLRenderPassDescriptor* mtl_render_pass = GetRenderPassMT().GetNativeDescriptor(m_mtl_cmd_buffer == nil); + + if (!m_mtl_cmd_buffer) + { + m_mtl_cmd_buffer = [GetCommandQueueMT().GetNativeCommandQueue() commandBuffer]; + assert(m_mtl_cmd_buffer != nil); + + m_mtl_cmd_buffer.label = MacOS::ConvertToNsType(GetName()); + } + + assert(mtl_render_pass != nil); + m_mtl_render_encoder = [m_mtl_cmd_buffer renderCommandEncoderWithDescriptor:mtl_render_pass]; + } + + assert(m_mtl_render_encoder != nil); + m_mtl_render_encoder.label = MacOS::ConvertToNsType(GetName()); RenderCommandListBase::Reset(sp_render_state, debug_group); } @@ -92,18 +123,13 @@ static MTLPrimitiveType PrimitiveTypeToMetal(RenderCommandList::Primitive primit RenderCommandListBase::SetName(name); - NSString* ns_name = MacOS::ConvertToNSType(name); + NSString* ns_name = MacOS::ConvertToNsType(name); if (m_mtl_render_encoder != nil) { m_mtl_render_encoder.label = ns_name; } - if (m_mtl_blit_encoder != nil) - { - m_mtl_blit_encoder.label = ns_name; - } - if (m_mtl_cmd_buffer != nil) { m_mtl_cmd_buffer.label = ns_name; @@ -115,7 +141,7 @@ static MTLPrimitiveType PrimitiveTypeToMetal(RenderCommandList::Primitive primit ITT_FUNCTION_TASK(); assert(m_mtl_render_encoder != nil); - NSString* ns_name = MacOS::ConvertToNSType(name); + NSString* ns_name = MacOS::ConvertToNsType(name); [m_mtl_render_encoder pushDebugGroup:ns_name]; } @@ -127,13 +153,13 @@ static MTLPrimitiveType PrimitiveTypeToMetal(RenderCommandList::Primitive primit [m_mtl_render_encoder popDebugGroup]; } -void RenderCommandListMT::SetVertexBuffers(const Buffer::Refs& vertex_buffers) +void RenderCommandListMT::SetVertexBuffers(const Refs& vertex_buffers) { ITT_FUNCTION_TASK(); RenderCommandListBase::SetVertexBuffers(vertex_buffers); - if (!m_draw_state.flags.vertex_buffers_changed) + if (!GetDrawingState().flags.vertex_buffers_changed) return; assert(m_mtl_render_encoder != nil); @@ -194,25 +220,23 @@ static MTLPrimitiveType PrimitiveTypeToMetal(RenderCommandList::Primitive primit baseInstance: start_instance]; } -void RenderCommandListMT::Commit(bool present_drawable) +void RenderCommandListMT::Commit() { ITT_FUNCTION_TASK(); assert(!IsCommitted()); - RenderCommandListBase::Commit(present_drawable); - - EndBlitEncoding(); - EndRenderEncoding(); + RenderCommandListBase::Commit(); - if (!m_mtl_cmd_buffer || m_is_parallel) - return; - - if (present_drawable) + if (m_mtl_render_encoder) { - [m_mtl_cmd_buffer presentDrawable: GetCommandQueueMT().GetContextMT().GetNativeDrawable()]; + [m_mtl_render_encoder endEncoding]; + m_mtl_render_encoder = nil; } + if (!m_mtl_cmd_buffer || IsParallel()) + return; + [m_mtl_cmd_buffer enqueue]; } @@ -222,7 +246,7 @@ static MTLPrimitiveType PrimitiveTypeToMetal(RenderCommandList::Primitive primit RenderCommandListBase::Execute(frame_index); - if (m_is_parallel || !m_mtl_cmd_buffer) + if (IsParallel() || !m_mtl_cmd_buffer) return; [m_mtl_cmd_buffer addCompletedHandler:^(id) { @@ -233,92 +257,13 @@ static MTLPrimitiveType PrimitiveTypeToMetal(RenderCommandList::Primitive primit m_mtl_cmd_buffer = nil; } -void RenderCommandListMT::InitializeCommandBuffer() -{ - ITT_FUNCTION_TASK(); - if (m_is_parallel || m_mtl_cmd_buffer != nil) - return; - - m_mtl_cmd_buffer = [GetCommandQueueMT().GetNativeCommandQueue() commandBuffer]; - assert(m_mtl_cmd_buffer != nil); - - m_mtl_cmd_buffer.label = MacOS::ConvertToNSType(GetName()); -} - -void RenderCommandListMT::StartRenderEncoding() -{ - ITT_FUNCTION_TASK(); - if (m_mtl_render_encoder != nil) - return; - - EndBlitEncoding(); - - // NOTE: If command buffer was not created for current frame yet, - // then render pass descriptor should be reset with new frame drawable - MTLRenderPassDescriptor* mtl_render_pass = GetPassMT().GetNativeDescriptor(!m_is_parallel && m_mtl_cmd_buffer == nil); - - InitializeCommandBuffer(); - - if (m_is_parallel) - { - ParallelRenderCommandListMT::Ptr sp_parallel_render_cmd_list = std::static_pointer_cast(m_wp_parallel_render_command_list.lock()); - assert(!!sp_parallel_render_cmd_list); - id& mtl_parallel_render_command_encoder = sp_parallel_render_cmd_list->GetNativeParallelRenderEncoder(); - m_mtl_render_encoder = [mtl_parallel_render_command_encoder renderCommandEncoder]; - } - else - { - assert(!!mtl_render_pass); - m_mtl_render_encoder = [m_mtl_cmd_buffer renderCommandEncoderWithDescriptor:mtl_render_pass]; - } - - assert(m_mtl_render_encoder != nil); - m_mtl_render_encoder.label = MacOS::ConvertToNSType(GetName()); -} - -void RenderCommandListMT::EndRenderEncoding() -{ - ITT_FUNCTION_TASK(); - if (m_mtl_render_encoder == nil) - return; - - [m_mtl_render_encoder endEncoding]; - m_mtl_render_encoder = nil; -} - -void RenderCommandListMT::StartBlitEncoding() -{ - ITT_FUNCTION_TASK(); - if (m_mtl_blit_encoder != nil) - return; - - InitializeCommandBuffer(); - EndRenderEncoding(); - - assert(m_mtl_cmd_buffer != nil); - m_mtl_blit_encoder = [m_mtl_cmd_buffer blitCommandEncoder]; - - assert(m_mtl_blit_encoder != nil); - m_mtl_blit_encoder.label = MacOS::ConvertToNSType(GetName()); -} - -void RenderCommandListMT::EndBlitEncoding() -{ - ITT_FUNCTION_TASK(); - if (m_mtl_blit_encoder == nil) - return; - - [m_mtl_blit_encoder endEncoding]; - m_mtl_blit_encoder = nil; -} - CommandQueueMT& RenderCommandListMT::GetCommandQueueMT() noexcept { ITT_FUNCTION_TASK(); - return static_cast(*m_sp_command_queue); + return static_cast(GetCommandQueue()); } -RenderPassMT& RenderCommandListMT::GetPassMT() +RenderPassMT& RenderCommandListMT::GetRenderPassMT() { ITT_FUNCTION_TASK(); return static_cast(GetPass()); diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderContextMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderContextMT.hh new file mode 100644 index 000000000..0728b1711 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderContextMT.hh @@ -0,0 +1,74 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/RenderContextMT.hh +Metal implementation of the render context interface. + +******************************************************************************/ + +#pragma once + +#include "ContextMT.hpp" + +#include + +#import +#import + +// Either use dispatch queue semaphore or fence primitives for CPU-GPU frames rendering synchronization +// NOTE: when fences are used for frames synchronization, +// application runs slower than expected when started from XCode, but runs normally when started from Finder +//#define USE_DISPATCH_QUEUE_SEMAPHORE + +namespace Methane::Graphics +{ + +class RenderContextMT final : public ContextMT +{ +public: + RenderContextMT(const Platform::AppEnvironment& env, DeviceBase& device, const Settings& settings); + ~RenderContextMT() override; + + // Context interface + void WaitForGpu(WaitFor wait_for) override; + + // RenderContext interface + bool ReadyToRender() const override; + void Resize(const FrameSize& frame_size) override; + void Present() override; + bool SetVSyncEnabled(bool vsync_enabled) override; + bool SetFrameBuffersCount(uint32_t frame_buffers_count) override; + float GetContentScalingFactor() const override; + Platform::AppView GetAppView() const override { return { m_app_view }; } + + // ContextBase overrides + void Initialize(DeviceBase& device, bool deferred_heap_allocation) override; + void Release() override; + + id GetNativeDrawable() { return m_app_view.currentDrawable; } + CommandQueueMT& GetRenderCommandQueueMT(); + +private: + AppViewMT* m_app_view; + id m_frame_capture_scope; +#ifdef USE_DISPATCH_QUEUE_SEMAPHORE + dispatch_semaphore_t m_dispatch_semaphore; +#endif +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderContextMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderContextMT.mm new file mode 100644 index 000000000..cf978b119 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderContextMT.mm @@ -0,0 +1,202 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/RenderContextMT.mm +Metal implementation of the render context interface. + +******************************************************************************/ + +#include "RenderContextMT.hh" +#include "RenderPassMT.hh" +#include "CommandQueueMT.hh" +#include "TypesMT.hh" + +#include +#include +#include + +namespace Methane::Graphics +{ + +Ptr RenderContext::Create(const Platform::AppEnvironment& env, Device& device, const RenderContext::Settings& settings) +{ + ITT_FUNCTION_TASK(); + DeviceBase& device_base = static_cast(device); + Ptr sp_render_context = std::make_shared(env, device_base, settings); + sp_render_context->Initialize(device_base, true); + return sp_render_context; +} + +RenderContextMT::RenderContextMT(const Platform::AppEnvironment& env, DeviceBase& device, const RenderContext::Settings& settings) + : ContextMT(device, settings) + , m_app_view([[AppViewMT alloc] initWithFrame: TypeConverterMT::CreateNSRect(settings.frame_size) + appWindow: env.ns_app_delegate.window + device: ContextMT::GetDeviceMT().GetNativeDevice() + pixelFormat: TypeConverterMT::DataFormatToMetalPixelType(settings.color_format) + drawableCount: settings.frame_buffers_count + vsyncEnabled: Methane::MacOS::ConvertToNsType(settings.vsync_enabled) + unsyncRefreshInterval: 1.0 / settings.unsync_max_fps]) + , m_frame_capture_scope([[MTLCaptureManager sharedCaptureManager] newCaptureScopeWithDevice:ContextMT::GetDeviceMT().GetNativeDevice()]) +#ifdef USE_DISPATCH_QUEUE_SEMAPHORE + , m_dispatch_semaphore(dispatch_semaphore_create(settings.frame_buffers_count)) +#endif +{ + ITT_FUNCTION_TASK(); + + m_frame_capture_scope.label = Methane::MacOS::ConvertToNsType(device.GetName() + " Capture Scope"); + [MTLCaptureManager sharedCaptureManager].defaultCaptureScope = m_frame_capture_scope; + + // bind metal context with application delegate + m_app_view.delegate = env.ns_app_delegate; + env.ns_app_delegate.view = m_app_view; + + // Start redrawing main view + m_app_view.redrawing = YES; +} + +RenderContextMT::~RenderContextMT() +{ + ITT_FUNCTION_TASK(); + + [m_app_view release]; + +#ifdef USE_DISPATCH_QUEUE_SEMAPHORE + dispatch_release(m_dispatch_semaphore); +#endif +} + +void RenderContextMT::Release() +{ + ITT_FUNCTION_TASK(); + + m_app_view.redrawing = NO; + +#ifdef USE_DISPATCH_QUEUE_SEMAPHORE + dispatch_release(m_dispatch_semaphore); +#endif + + ContextMT::Release(); +} + +void RenderContextMT::Initialize(DeviceBase& device, bool deferred_heap_allocation) +{ + ITT_FUNCTION_TASK(); + + ContextMT::Initialize(device, deferred_heap_allocation); + +#ifdef USE_DISPATCH_QUEUE_SEMAPHORE + m_dispatch_semaphore = dispatch_semaphore_create(GetSettings().frame_buffers_count); +#endif + + m_app_view.redrawing = YES; +} + +bool RenderContextMT::ReadyToRender() const +{ + ITT_FUNCTION_TASK(); + return m_app_view.currentDrawable != nil; +} + +void RenderContextMT::WaitForGpu(WaitFor wait_for) +{ + ITT_FUNCTION_TASK(); + +#ifdef USE_DISPATCH_QUEUE_SEMAPHORE + if (wait_for != WaitFor::FramePresented) + ContextMT::WaitForGpu(wait_for); +#else + ContextMT::WaitForGpu(wait_for); +#endif + + if (wait_for == WaitFor::FramePresented) + { +#ifdef USE_DISPATCH_QUEUE_SEMAPHORE + OnGpuWaitStart(wait_for); + dispatch_semaphore_wait(m_dispatch_semaphore, DISPATCH_TIME_FOREVER); + OnGpuWaitComplete(wait_for); +#endif + UpdateFrameBufferIndex(); + [m_frame_capture_scope beginScope]; + } +} + +void RenderContextMT::Resize(const FrameSize& frame_size) +{ + ITT_FUNCTION_TASK(); + ContextMT::Resize(frame_size); +} + +void RenderContextMT::Present() +{ + ITT_FUNCTION_TASK(); + ContextMT::Present(); + + id mtl_cmd_buffer = [GetRenderCommandQueueMT().GetNativeCommandQueue() commandBuffer]; + mtl_cmd_buffer.label = MacOS::ConvertToNsType(GetName() + " Present Command"); + [mtl_cmd_buffer presentDrawable:GetNativeDrawable()]; +#ifdef USE_DISPATCH_QUEUE_SEMAPHORE + const bool signal_frame_fence = false; + [mtl_cmd_buffer addCompletedHandler:^(id _Nonnull) { + dispatch_semaphore_signal(m_dispatch_semaphore); + }]; +#else + const bool signal_frame_fence = true; +#endif + [mtl_cmd_buffer commit]; + + [m_frame_capture_scope endScope]; + + ContextMT::OnCpuPresentComplete(signal_frame_fence); +} + +bool RenderContextMT::SetVSyncEnabled(bool vsync_enabled) +{ + ITT_FUNCTION_TASK(); + if (ContextMT::SetVSyncEnabled(vsync_enabled)) + { + m_app_view.vsyncEnabled = vsync_enabled; + return true; + } + return false; +} + +bool RenderContextMT::SetFrameBuffersCount(uint32_t frame_buffers_count) +{ + ITT_FUNCTION_TASK(); + frame_buffers_count = std::min(std::max(2u, frame_buffers_count), 3u); // Metal supports only 2 or 3 drawable buffers + if (ContextMT::SetFrameBuffersCount(frame_buffers_count)) + { + m_app_view.drawableCount = frame_buffers_count; + return true; + } + return false; +} + +float RenderContextMT::GetContentScalingFactor() const +{ + ITT_FUNCTION_TASK(); + return static_cast(m_app_view.appWindow.backingScaleFactor); +} + +CommandQueueMT& RenderContextMT::GetRenderCommandQueueMT() +{ + ITT_FUNCTION_TASK(); + return static_cast(ContextMT::GetRenderCommandQueue()); +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderPassMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderPassMT.hh index c202d912b..2e9e5212b 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderPassMT.hh +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderPassMT.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,12 +30,12 @@ Metal implementation of the render pass interface. namespace Methane::Graphics { -class ContextMT; +struct IContextMT; -class RenderPassMT : public RenderPassBase +class RenderPassMT final : public RenderPassBase { public: - RenderPassMT(ContextBase& context, const Settings& settings); + RenderPassMT(RenderContextBase& context, const Settings& settings); // RenderPass interface void Update(const Settings& settings) override; @@ -44,8 +44,8 @@ public: MTLRenderPassDescriptor* GetNativeDescriptor(bool reset); -protected: - ContextMT& GetContextMT() noexcept; +private: + IContextMT& GetContextMT() noexcept; MTLRenderPassDescriptor* m_mtl_pass_descriptor; }; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderPassMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderPassMT.mm index 363a68bda..2e092bc6a 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderPassMT.mm +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderPassMT.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,11 +22,11 @@ ******************************************************************************/ #include "RenderPassMT.hh" -#include "ContextMT.hh" +#include "RenderContextMT.hh" #include "TextureMT.hh" #include "TypesMT.hh" -#include +#include namespace Methane::Graphics { @@ -57,26 +57,23 @@ static MTLLoadAction GetMTLLoadAction(RenderPass::Attachment::LoadAction load_ac return MTLLoadActionDontCare; } -RenderPass::Ptr RenderPass::Create(Context& context, const Settings& settings) +Ptr RenderPass::Create(RenderContext& context, const Settings& settings) { ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context), settings); + return std::make_shared(dynamic_cast(context), settings); } -RenderPassMT::RenderPassMT(ContextBase& context, const Settings& settings) +RenderPassMT::RenderPassMT(RenderContextBase& context, const Settings& settings) : RenderPassBase(context, settings) { ITT_FUNCTION_TASK(); - Reset(); } void RenderPassMT::Update(const Settings& settings) { ITT_FUNCTION_TASK(); - - m_settings = settings; - + RenderPassBase::Update(settings); Reset(); } @@ -85,9 +82,10 @@ static MTLLoadAction GetMTLLoadAction(RenderPass::Attachment::LoadAction load_ac ITT_FUNCTION_TASK(); m_mtl_pass_descriptor = [MTLRenderPassDescriptor renderPassDescriptor]; + const Settings& settings = GetSettings(); uint32_t color_attach_index = 0; - for(ColorAttachment& color_attach : m_settings.color_attachments) + for(const ColorAttachment& color_attach : settings.color_attachments) { if (color_attach.wp_texture.expired()) { @@ -108,29 +106,28 @@ static MTLLoadAction GetMTLLoadAction(RenderPass::Attachment::LoadAction load_ac color_attach_index++; } - if (!m_settings.depth_attachment.wp_texture.expired()) + if (!settings.depth_attachment.wp_texture.expired()) { - const TextureMT& depth_texture = static_cast(*m_settings.depth_attachment.wp_texture.lock()); + const TextureMT& depth_texture = static_cast(*settings.depth_attachment.wp_texture.lock()); m_mtl_pass_descriptor.depthAttachment.texture = depth_texture.GetNativeTexture(); - m_mtl_pass_descriptor.depthAttachment.clearDepth = m_settings.depth_attachment.clear_value; - m_mtl_pass_descriptor.depthAttachment.loadAction = GetMTLLoadAction(m_settings.depth_attachment.load_action); - m_mtl_pass_descriptor.depthAttachment.storeAction = GetMTLStoreAction(m_settings.depth_attachment.store_action); + m_mtl_pass_descriptor.depthAttachment.clearDepth = settings.depth_attachment.clear_value; + m_mtl_pass_descriptor.depthAttachment.loadAction = GetMTLLoadAction(settings.depth_attachment.load_action); + m_mtl_pass_descriptor.depthAttachment.storeAction = GetMTLStoreAction(settings.depth_attachment.store_action); } - if (!m_settings.stencil_attachment.wp_texture.expired()) + if (!settings.stencil_attachment.wp_texture.expired()) { - const TextureMT& stencil_texture = static_cast(*m_settings.stencil_attachment.wp_texture.lock()); + const TextureMT& stencil_texture = static_cast(*settings.stencil_attachment.wp_texture.lock()); m_mtl_pass_descriptor.stencilAttachment.texture = stencil_texture.GetNativeTexture(); - m_mtl_pass_descriptor.stencilAttachment.clearStencil = m_settings.stencil_attachment.clear_value; - m_mtl_pass_descriptor.stencilAttachment.loadAction = GetMTLLoadAction(m_settings.stencil_attachment.load_action); - m_mtl_pass_descriptor.stencilAttachment.storeAction = GetMTLStoreAction(m_settings.stencil_attachment.store_action); + m_mtl_pass_descriptor.stencilAttachment.clearStencil = settings.stencil_attachment.clear_value; + m_mtl_pass_descriptor.stencilAttachment.loadAction = GetMTLLoadAction(settings.stencil_attachment.load_action); + m_mtl_pass_descriptor.stencilAttachment.storeAction = GetMTLStoreAction(settings.stencil_attachment.store_action); } } MTLRenderPassDescriptor* RenderPassMT::GetNativeDescriptor(bool reset) { ITT_FUNCTION_TASK(); - if (reset) { Reset(); @@ -138,10 +135,10 @@ static MTLLoadAction GetMTLLoadAction(RenderPass::Attachment::LoadAction load_ac return m_mtl_pass_descriptor; } -ContextMT& RenderPassMT::GetContextMT() noexcept +IContextMT& RenderPassMT::GetContextMT() noexcept { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(GetRenderContext()); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderStateMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderStateMT.hh index fce875a33..8574ce48c 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderStateMT.hh +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderStateMT.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -32,12 +32,12 @@ Metal implementation of the render state interface. namespace Methane::Graphics { -class ContextMT; +class RenderContextMT; -class RenderStateMT : public RenderStateBase +class RenderStateMT final : public RenderStateBase { public: - RenderStateMT(ContextBase& context, const Settings& settings); + RenderStateMT(RenderContextBase& context, const Settings& settings); ~RenderStateMT() override; // RenderState interface @@ -51,13 +51,17 @@ public: // Object interface void SetName(const std::string& name) override; + void InitializeNativeStates(); + void InitializeNativePipelineState(); + void InitializeNativeDepthStencilState(); + id& GetNativePipelineState(); id& GetNativeDepthStencilState(); MTLCullMode GetNativeCullMode() const noexcept { return m_mtl_cull_mode; } MTLWinding GetNativeFrontFaceWinding() const noexcept { return m_mtl_front_face_winding; } -protected: - ContextMT& GetContextMT() noexcept; +private: + RenderContextMT& GetRenderContextMT(); void ResetNativeState(); diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderStateMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderStateMT.mm index 416ef627e..7103196dc 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderStateMT.mm +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/RenderStateMT.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,18 +22,14 @@ ******************************************************************************/ #include "RenderStateMT.hh" -#include "ContextMT.hh" -#include "DeviceMT.hh" +#include "RenderContextMT.hh" #include "RenderCommandListMT.hh" #include "ProgramMT.hh" #include "ShaderMT.hh" #include "TypesMT.hh" -#include #include -#include - -#include +#include namespace Methane::Graphics { @@ -53,7 +49,6 @@ static MTLCullMode ConvertRasterizerCullModeToMetal(RenderState::Rasterizer::Cul return MTLCullModeNone; } - static MTLTriangleFillMode ConvertRasterizerFillModeToMetal(RenderState::Rasterizer::FillMode fill_mode) noexcept { ITT_FUNCTION_TASK(); @@ -74,7 +69,7 @@ static MTLColorWriteMask ConvertRenderTargetWriteMaskToMetal(RenderState::Blendi using ColorChannel = RenderState::Blending::ColorChannel; - MTLColorWriteMask mtl_color_write_mask = 0; + MTLColorWriteMask mtl_color_write_mask = 0u; if (rt_write_mask & ColorChannel::Red) mtl_color_write_mask |= MTLColorWriteMaskRed; if (rt_write_mask & ColorChannel::Green) @@ -99,7 +94,6 @@ static MTLBlendOperation ConvertBlendingOperationToMetal(RenderState::Blending:: case BlendOp::ReverseSubtract: return MTLBlendOperationReverseSubtract; case BlendOp::Minimum: return MTLBlendOperationMin; case BlendOp::Maximum: return MTLBlendOperationMax; - default: assert(0); } return MTLBlendOperationAdd; } @@ -131,7 +125,6 @@ static MTLBlendFactor ConvertBlendingFactorToMetal(RenderState::Blending::Factor case BlendFactor::OneMinusSource1Color: return MTLBlendFactorOneMinusSource1Color; case BlendFactor::Source1Alpha: return MTLBlendFactorSource1Alpha; case BlendFactor::OneMinusSource1Alpha: return MTLBlendFactorOneMinusSource1Alpha; - default: assert(0); } return MTLBlendFactorZero; } @@ -152,7 +145,6 @@ static MTLStencilOperation ConvertStencilOperationToMetal(RenderState::Stencil:: case StencilOperation::DecrementClamp: return MTLStencilOperationDecrementClamp; case StencilOperation::IncrementWrap: return MTLStencilOperationIncrementWrap; case StencilOperation::DecrementWrap: return MTLStencilOperationDecrementWrap; - default: assert(0); } return MTLStencilOperationKeep; } @@ -182,13 +174,13 @@ static MTLWinding ConvertRasterizerFrontWindingToMetal(bool is_front_counter_clo return mtl_stencil_desc; } -RenderState::Ptr RenderState::Create(Context& context, const RenderState::Settings& state_settings) +Ptr RenderState::Create(RenderContext& context, const RenderState::Settings& state_settings) { ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context), state_settings); + return std::make_shared(dynamic_cast(context), state_settings); } -RenderStateMT::RenderStateMT(ContextBase& context, const Settings& settings) +RenderStateMT::RenderStateMT(RenderContextBase& context, const Settings& settings) : RenderStateBase(context, settings) { ITT_FUNCTION_TASK(); @@ -216,8 +208,8 @@ static MTLWinding ConvertRasterizerFrontWindingToMetal(bool is_front_counter_clo RenderStateBase::Reset(settings); [m_mtl_pipeline_state_desc release]; [m_mtl_depth_stencil_state_desc release]; - - ProgramMT& metal_program = static_cast(*m_settings.sp_program); + + ProgramMT& metal_program = static_cast(*settings.sp_program); // Program state m_mtl_pipeline_state_desc = [[MTLRenderPipelineDescriptor alloc] init]; @@ -226,24 +218,24 @@ static MTLWinding ConvertRasterizerFrontWindingToMetal(bool is_front_counter_clo m_mtl_pipeline_state_desc.vertexDescriptor = metal_program.GetNativeVertexDescriptor(); // Rasterizer state - m_mtl_pipeline_state_desc.sampleCount = m_settings.rasterizer.sample_count; - m_mtl_pipeline_state_desc.alphaToCoverageEnabled = m_settings.rasterizer.alpha_to_coverage_enabled ? YES : NO; + m_mtl_pipeline_state_desc.sampleCount = settings.rasterizer.sample_count; + m_mtl_pipeline_state_desc.alphaToCoverageEnabled = settings.rasterizer.alpha_to_coverage_enabled; m_mtl_pipeline_state_desc.alphaToOneEnabled = NO; // not supported by Methane // Blending state const std::vector& rt_color_formats = metal_program.GetSettings().color_formats; - for (uint32_t rt_index = 0; rt_index < m_settings.blending.render_targets.size(); ++rt_index) + for (uint32_t rt_index = 0; rt_index < settings.blending.render_targets.size(); ++rt_index) { - const Blending::RenderTarget& render_target = m_settings.blending.is_independent - ? m_settings.blending.render_targets[rt_index] - : m_settings.blending.render_targets[0]; + const Blending::RenderTarget& render_target = settings.blending.is_independent + ? settings.blending.render_targets[rt_index] + : settings.blending.render_targets[0]; // Set render target blending state for color attachment MTLRenderPipelineColorAttachmentDescriptor* mtl_color_attach = m_mtl_pipeline_state_desc.colorAttachments[rt_index]; mtl_color_attach.pixelFormat = rt_index < rt_color_formats.size() ? TypeConverterMT::DataFormatToMetalPixelType(rt_color_formats[rt_index]) : MTLPixelFormatInvalid; - mtl_color_attach.blendingEnabled = render_target.blend_enabled && rt_index < rt_color_formats.size() ? YES : NO; + mtl_color_attach.blendingEnabled = render_target.blend_enabled && rt_index < rt_color_formats.size(); mtl_color_attach.writeMask = ConvertRenderTargetWriteMaskToMetal(render_target.write_mask); mtl_color_attach.rgbBlendOperation = ConvertBlendingOperationToMetal(render_target.rgb_blend_op); mtl_color_attach.alphaBlendOperation = ConvertBlendingOperationToMetal(render_target.alpha_blend_op); @@ -260,25 +252,25 @@ static MTLWinding ConvertRasterizerFrontWindingToMetal(bool is_front_counter_clo // Depth-stencil state m_mtl_depth_stencil_state_desc = [[MTLDepthStencilDescriptor alloc] init]; - m_mtl_depth_stencil_state_desc.depthWriteEnabled = m_settings.depth.write_enabled && depth_format != PixelFormat::Unknown ? YES : NO; - m_mtl_depth_stencil_state_desc.depthCompareFunction = m_settings.depth.enabled && depth_format != PixelFormat::Unknown - ? TypeConverterMT::CompareFunctionToMetal(m_settings.depth.compare) + m_mtl_depth_stencil_state_desc.depthWriteEnabled = settings.depth.write_enabled && depth_format != PixelFormat::Unknown; + m_mtl_depth_stencil_state_desc.depthCompareFunction = settings.depth.enabled && depth_format != PixelFormat::Unknown + ? TypeConverterMT::CompareFunctionToMetal(settings.depth.compare) : MTLCompareFunctionAlways; - m_mtl_depth_stencil_state_desc.backFaceStencil = ConvertStencilDescriptorToMetal(m_settings.stencil, false); - m_mtl_depth_stencil_state_desc.frontFaceStencil = ConvertStencilDescriptorToMetal(m_settings.stencil, true); + m_mtl_depth_stencil_state_desc.backFaceStencil = ConvertStencilDescriptorToMetal(settings.stencil, false); + m_mtl_depth_stencil_state_desc.frontFaceStencil = ConvertStencilDescriptorToMetal(settings.stencil, true); // Separate state parameters - m_mtl_fill_mode = ConvertRasterizerFillModeToMetal(m_settings.rasterizer.fill_mode); - m_mtl_cull_mode = ConvertRasterizerCullModeToMetal(m_settings.rasterizer.cull_mode); - m_mtl_front_face_winding = ConvertRasterizerFrontWindingToMetal(m_settings.rasterizer.is_front_counter_clockwise); + m_mtl_fill_mode = ConvertRasterizerFillModeToMetal(settings.rasterizer.fill_mode); + m_mtl_cull_mode = ConvertRasterizerCullModeToMetal(settings.rasterizer.cull_mode); + m_mtl_front_face_winding = ConvertRasterizerFrontWindingToMetal(settings.rasterizer.is_front_counter_clockwise); - if (!m_settings.viewports.empty()) + if (!settings.viewports.empty()) { - SetViewports(m_settings.viewports); + SetViewports(settings.viewports); } - if (!m_settings.scissor_rects.empty()) + if (!settings.scissor_rects.empty()) { - SetScissorRects(m_settings.scissor_rects); + SetScissorRects(settings.scissor_rects); } ResetNativeState(); @@ -317,10 +309,11 @@ static MTLWinding ConvertRasterizerFrontWindingToMetal(bool is_front_counter_clo } if (state_groups & Group::BlendingColor) { - [mtl_cmd_encoder setBlendColorRed:m_settings.blending_color.r() - green:m_settings.blending_color.g() - blue:m_settings.blending_color.b() - alpha:m_settings.blending_color.a()]; + const Settings& settings = GetSettings(); + [mtl_cmd_encoder setBlendColorRed:settings.blending_color.GetR() + green:settings.blending_color.GetG() + blue:settings.blending_color.GetB() + alpha:settings.blending_color.GetA()]; } } @@ -334,12 +327,12 @@ static MTLWinding ConvertRasterizerFrontWindingToMetal(bool is_front_counter_clo for(const Viewport& viewport : viewports) { MTLViewport mtl_viewport = { }; - mtl_viewport.originX = viewport.origin.x(); - mtl_viewport.originY = viewport.origin.y(); + mtl_viewport.originX = viewport.origin.GetX(); + mtl_viewport.originY = viewport.origin.GetY(); mtl_viewport.width = viewport.size.width; mtl_viewport.height = viewport.size.height; - mtl_viewport.znear = viewport.origin.z(); - mtl_viewport.zfar = viewport.origin.z() + viewport.size.depth; + mtl_viewport.znear = viewport.origin.GetZ(); + mtl_viewport.zfar = viewport.origin.GetZ() + viewport.size.depth; m_mtl_viewports.emplace_back(std::move(mtl_viewport)); } } @@ -354,8 +347,8 @@ static MTLWinding ConvertRasterizerFrontWindingToMetal(bool is_front_counter_clo for(const ScissorRect& scissor_rect : scissor_rects) { MTLScissorRect mtl_scissor_rect = {}; - mtl_scissor_rect.x = static_cast(scissor_rect.origin.x()); - mtl_scissor_rect.y = static_cast(scissor_rect.origin.y()); + mtl_scissor_rect.x = static_cast(scissor_rect.origin.GetX()); + mtl_scissor_rect.y = static_cast(scissor_rect.origin.GetY()); mtl_scissor_rect.width = static_cast(scissor_rect.size.width); mtl_scissor_rect.height = static_cast(scissor_rect.size.height); m_mtl_scissor_rects.emplace_back(std::move(mtl_scissor_rect)); @@ -368,26 +361,55 @@ static MTLWinding ConvertRasterizerFrontWindingToMetal(bool is_front_counter_clo RenderStateBase::SetName(name); - NSString* ns_name = Methane::MacOS::ConvertToNSType(name); + NSString* ns_name = Methane::MacOS::ConvertToNsType(name); m_mtl_pipeline_state_desc.label = ns_name; m_mtl_depth_stencil_state_desc.label = ns_name; ResetNativeState(); } + +void RenderStateMT::InitializeNativeStates() +{ + ITT_FUNCTION_TASK(); + InitializeNativePipelineState(); + InitializeNativeDepthStencilState(); +} -id& RenderStateMT::GetNativePipelineState() +void RenderStateMT::InitializeNativePipelineState() +{ + ITT_FUNCTION_TASK(); + if (m_mtl_pipeline_state) + return; + + NSError* ns_error = nil; + m_mtl_pipeline_state = [GetRenderContextMT().GetDeviceMT().GetNativeDevice() newRenderPipelineStateWithDescriptor:m_mtl_pipeline_state_desc error:&ns_error]; + if (!m_mtl_pipeline_state) + { + const std::string error_msg = MacOS::ConvertFromNsType([ns_error localizedDescription]); + throw std::runtime_error("Failed to create Metal pipeline state: " + error_msg); + } +} + +void RenderStateMT::InitializeNativeDepthStencilState() { ITT_FUNCTION_TASK(); + if (m_mtl_depth_state) + return; + + assert(m_mtl_depth_stencil_state_desc != nil); + m_mtl_depth_state = [GetRenderContextMT().GetDeviceMT().GetNativeDevice() newDepthStencilStateWithDescriptor:m_mtl_depth_stencil_state_desc]; + if (!m_mtl_depth_state) + { + throw std::runtime_error("Failed to create Metal depth state."); + } +} +id& RenderStateMT::GetNativePipelineState() +{ + ITT_FUNCTION_TASK(); if (!m_mtl_pipeline_state) { - NSError* ns_error = nil; - m_mtl_pipeline_state = [GetContextMT().GetDeviceMT().GetNativeDevice() newRenderPipelineStateWithDescriptor:m_mtl_pipeline_state_desc error:&ns_error]; - if (!m_mtl_pipeline_state) - { - const std::string error_msg = MacOS::ConvertFromNSType([ns_error localizedDescription]); - throw std::runtime_error("Failed to create Metal pipeline state: " + error_msg); - } + InitializeNativePipelineState(); } return m_mtl_pipeline_state; } @@ -395,15 +417,9 @@ static MTLWinding ConvertRasterizerFrontWindingToMetal(bool is_front_counter_clo id& RenderStateMT::GetNativeDepthStencilState() { ITT_FUNCTION_TASK(); - if (!m_mtl_depth_state) { - assert(m_mtl_depth_stencil_state_desc != nil); - m_mtl_depth_state = [GetContextMT().GetDeviceMT().GetNativeDevice() newDepthStencilStateWithDescriptor:m_mtl_depth_stencil_state_desc]; - if (!m_mtl_depth_state) - { - throw std::runtime_error("Failed to create Metal depth state."); - } + InitializeNativeStates(); } return m_mtl_depth_state; } @@ -419,10 +435,10 @@ static MTLWinding ConvertRasterizerFrontWindingToMetal(bool is_front_counter_clo m_mtl_depth_state = nil; } -ContextMT& RenderStateMT::GetContextMT() noexcept +RenderContextMT& RenderStateMT::GetRenderContextMT() { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return dynamic_cast(GetRenderContext()); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ResourceMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ResourceMT.hh index 76da2444c..c6e62be1a 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ResourceMT.hh +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ResourceMT.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,14 +30,12 @@ Metal implementation of the resource interface. namespace Methane::Graphics { -class ContextMT; +struct IContextMT; struct ResourceContainerMT; class ResourceMT : public ResourceBase { public: - using Ptr = std::shared_ptr; - class ReleasePoolMT : public ReleasePool { public: @@ -54,7 +52,7 @@ public: ResourceMT(Type type, Usage::Mask usage_mask, ContextBase& context, const DescriptorByUsage& descriptor_by_usage); protected: - ContextMT& GetContextMT() noexcept; + IContextMT& GetContextMT() noexcept; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ResourceMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ResourceMT.mm index 23349237f..f89b3a9c2 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ResourceMT.mm +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ResourceMT.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,16 +22,15 @@ ******************************************************************************/ #include "ResourceMT.hh" -#include "ContextMT.hh" +#include "ContextMT.h" #include "BufferMT.hh" #include "TextureMT.hh" -#include +#include +#include #include -#import - namespace Methane::Graphics { @@ -41,7 +40,7 @@ std::vector> textures; }; -ResourceBase::ReleasePool::Ptr ResourceBase::ReleasePool::Create() +Ptr ResourceBase::ReleasePool::Create() { ITT_FUNCTION_TASK(); return std::make_shared(); @@ -94,10 +93,10 @@ ITT_FUNCTION_TASK(); } -ContextMT& ResourceMT::GetContextMT() noexcept +IContextMT& ResourceMT::GetContextMT() noexcept { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(GetContext()); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/SamplerMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/SamplerMT.hh index fc2bd2c97..68a789821 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/SamplerMT.hh +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/SamplerMT.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,9 +30,9 @@ Metal implementation of the sampler interface. namespace Methane::Graphics { -class ContextMT; +struct IContextMT; -class SamplerMT : public SamplerBase +class SamplerMT final : public SamplerBase { public: SamplerMT(ContextBase& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage); @@ -43,11 +43,9 @@ public: const id& GetNativeSamplerState() const noexcept { return m_mtl_sampler_state; } -protected: - void ResetSampletState(); +private: + void ResetSamplerState(); - ContextMT& GetContextMT() noexcept; - MTLSamplerDescriptor* m_mtl_sampler_desc = nullptr; id m_mtl_sampler_state = nil; }; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/SamplerMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/SamplerMT.mm index 125b0d713..97d4a8939 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/SamplerMT.mm +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/SamplerMT.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,12 +22,13 @@ ******************************************************************************/ #include "SamplerMT.hh" -#include "ContextMT.hh" +#include "ContextMT.h" #include "DeviceMT.hh" #include "TypesMT.hh" -#include -#import +#include +#include +#include namespace Methane::Graphics { @@ -89,10 +90,10 @@ static MTLSamplerBorderColor ConvertBorderColorToMetal(const SamplerBase::Border } } -Sampler::Ptr Sampler::Create(Context& context, const Sampler::Settings& settings, const DescriptorByUsage& descriptor_by_usage) +Ptr Sampler::Create(Context& context, const Sampler::Settings& settings, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context), settings, descriptor_by_usage); + return std::make_shared(dynamic_cast(context), settings, descriptor_by_usage); } SamplerMT::SamplerMT(ContextBase& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage) @@ -103,22 +104,22 @@ static MTLSamplerBorderColor ConvertBorderColorToMetal(const SamplerBase::Border InitializeDefaultDescriptors(); - m_mtl_sampler_desc.rAddressMode = ConvertAddressModeToMetal(m_settings.address.r); - m_mtl_sampler_desc.sAddressMode = ConvertAddressModeToMetal(m_settings.address.s); - m_mtl_sampler_desc.tAddressMode = ConvertAddressModeToMetal(m_settings.address.t); + m_mtl_sampler_desc.rAddressMode = ConvertAddressModeToMetal(settings.address.r); + m_mtl_sampler_desc.sAddressMode = ConvertAddressModeToMetal(settings.address.s); + m_mtl_sampler_desc.tAddressMode = ConvertAddressModeToMetal(settings.address.t); - m_mtl_sampler_desc.minFilter = ConvertMinMagFilterToMetal(m_settings.filter.min); - m_mtl_sampler_desc.magFilter = ConvertMinMagFilterToMetal(m_settings.filter.mag); - m_mtl_sampler_desc.mipFilter = ConvertMipFilterToMetal(m_settings.filter.mip); + m_mtl_sampler_desc.minFilter = ConvertMinMagFilterToMetal(settings.filter.min); + m_mtl_sampler_desc.magFilter = ConvertMinMagFilterToMetal(settings.filter.mag); + m_mtl_sampler_desc.mipFilter = ConvertMipFilterToMetal(settings.filter.mip); - m_mtl_sampler_desc.lodMinClamp = m_settings.lod.min; - m_mtl_sampler_desc.lodMaxClamp = m_settings.lod.max; + m_mtl_sampler_desc.lodMinClamp = settings.lod.min; + m_mtl_sampler_desc.lodMaxClamp = settings.lod.max; - m_mtl_sampler_desc.maxAnisotropy = m_settings.max_anisotropy; - m_mtl_sampler_desc.compareFunction = TypeConverterMT::CompareFunctionToMetal(m_settings.compare_function); - m_mtl_sampler_desc.borderColor = ConvertBorderColorToMetal(m_settings.border_color); - - ResetSampletState(); + m_mtl_sampler_desc.maxAnisotropy = settings.max_anisotropy; + m_mtl_sampler_desc.compareFunction = TypeConverterMT::CompareFunctionToMetal(settings.compare_function); + m_mtl_sampler_desc.borderColor = ConvertBorderColorToMetal(settings.border_color); + + ResetSamplerState(); } SamplerMT::~SamplerMT() @@ -135,13 +136,13 @@ static MTLSamplerBorderColor ConvertBorderColorToMetal(const SamplerBase::Border SamplerBase::SetName(name); - assert(!!m_mtl_sampler_desc); - m_mtl_sampler_desc.label = Methane::MacOS::ConvertToNSType(name); - - ResetSampletState(); + assert(m_mtl_sampler_desc != nil); + m_mtl_sampler_desc.label = Methane::MacOS::ConvertToNsType(name); + + ResetSamplerState(); } -void SamplerMT::ResetSampletState() +void SamplerMT::ResetSamplerState() { ITT_FUNCTION_TASK(); @@ -154,10 +155,4 @@ static MTLSamplerBorderColor ConvertBorderColorToMetal(const SamplerBase::Border m_mtl_sampler_state = [GetContextMT().GetDeviceMT().GetNativeDevice() newSamplerStateWithDescriptor:m_mtl_sampler_desc]; } -ContextMT& SamplerMT::GetContextMT() noexcept -{ - ITT_FUNCTION_TASK(); - return static_cast(m_context); -} - } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ShaderMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ShaderMT.hh index a0dd9bb5e..7e01a4601 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ShaderMT.hh +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ShaderMT.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -27,60 +27,27 @@ Metal implementation of the shader interface. #import -#include -#include - namespace Methane::Graphics { -class ContextMT; +struct IContextMT; class ProgramMT; -class ShaderMT : public ShaderBase +class ShaderMT final : public ShaderBase { public: - class ResourceBindingMT : public ResourceBindingBase - { - public: - struct Settings - { - ResourceBindingBase::Settings base; - uint32_t argument_index; - }; - - ResourceBindingMT(ContextBase& context, const Settings& settings); - ResourceBindingMT(const ResourceBindingMT& other) = default; - - // ResourceBinding interface - void SetResourceLocations(const Resource::Locations& resource_locations) override; - - const Settings& GetSettings() const noexcept { return m_settings; } - const std::vector>& GetNativeSamplerStates() const { return m_mtl_sampler_states; } - const std::vector>& GetNativeTextures() const { return m_mtl_textures; } - const std::vector>& GetNativeBuffers() const { return m_mtl_buffers; } - const std::vector& GetBufferOffsets() const { return m_mtl_buffer_offsets; } - - protected: - const Settings m_settings; - std::vector> m_mtl_sampler_states; - std::vector> m_mtl_textures; - std::vector> m_mtl_buffers; - std::vector m_mtl_buffer_offsets; - }; - - ShaderMT(Shader::Type shader_type, ContextMT& context, const Settings& settings); + ShaderMT(Shader::Type shader_type, ContextBase& context, const Settings& settings); ~ShaderMT() override; // ShaderBase interface - ResourceBindings GetResourceBindings(const std::set& constant_argument_names, - const std::set& addressable_argument_names) const override; + ArgumentBindings GetArgumentBindings(const Program::ArgumentDescriptions& argument_descriptions) const override; id& GetNativeFunction() noexcept { return m_mtl_function; } MTLVertexDescriptor* GetNativeVertexDescriptor(const ProgramMT& program) const; void SetNativeArguments(NSArray* mtl_arguments) noexcept { m_mtl_arguments = mtl_arguments; } -protected: - ContextMT& GetContextMT() noexcept; +private: + IContextMT& GetContextMT() noexcept; id m_mtl_function; NSArray* m_mtl_arguments = nil; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ShaderMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ShaderMT.mm index d52f966a1..7b0385cc7 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ShaderMT.mm +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/ShaderMT.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,16 +23,16 @@ #include "ShaderMT.hh" #include "ProgramMT.hh" -#include "SamplerMT.hh" -#include "BufferMT.hh" -#include "TextureMT.hh" -#include "ContextMT.hh" +#include "ProgramLibraryMT.hh" +#include "ProgramBindingsMT.hh" +#include "ContextMT.h" #include "TypesMT.hh" -#include +#include #include +#include -#include +#include namespace Methane::Graphics { @@ -90,67 +90,17 @@ static MTLVertexStepFunction GetVertexStepFunction(StepType step_type) noexcept return "Unknown"; } #endif - -Shader::ResourceBinding::Ptr Shader::ResourceBinding::CreateCopy(const ResourceBinding& other_resource_binging) -{ - ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(other_resource_binging)); -} - -ShaderMT::ResourceBindingMT::ResourceBindingMT(ContextBase& context, const Settings& settings) - : ResourceBindingBase(context, settings.base) - , m_settings(settings) -{ - ITT_FUNCTION_TASK(); -} - -void ShaderMT::ResourceBindingMT::SetResourceLocations(const Resource::Locations& resource_locations) -{ - ITT_FUNCTION_TASK(); - ResourceBindingBase::SetResourceLocations(resource_locations); - - m_mtl_sampler_states.clear(); - m_mtl_textures.clear(); - m_mtl_buffers.clear(); - m_mtl_buffer_offsets.clear(); - - switch(m_settings.base.resource_type) - { - case Resource::Type::Sampler: - m_mtl_sampler_states.reserve(m_resource_locations.size()); - std::transform(m_resource_locations.begin(), m_resource_locations.end(), std::back_inserter(m_mtl_sampler_states), - [](const Resource::Location& resource_location) - { return dynamic_cast(resource_location.GetResource()).GetNativeSamplerState(); }); - break; - - case Resource::Type::Texture: - m_mtl_textures.reserve(m_resource_locations.size()); - std::transform(m_resource_locations.begin(), m_resource_locations.end(), std::back_inserter(m_mtl_textures), - [](const Resource::Location& resource_location) - { return dynamic_cast(resource_location.GetResource()).GetNativeTexture(); }); - break; - case Resource::Type::Buffer: - m_mtl_buffers.reserve(m_resource_locations.size()); - m_mtl_buffer_offsets.reserve(m_resource_locations.size()); - for (const Resource::Location& resource_location : m_resource_locations) - { - m_mtl_buffers.push_back(dynamic_cast(resource_location.GetResource()).GetNativeBuffer()); - m_mtl_buffer_offsets.push_back(static_cast(resource_location.GetOffset())); - } - break; - } -} -Shader::Ptr Shader::Create(Shader::Type shader_type, Context& context, const Settings& settings) +Ptr Shader::Create(Shader::Type shader_type, Context& context, const Settings& settings) { ITT_FUNCTION_TASK(); - return std::make_shared(shader_type, static_cast(context), settings); + return std::make_shared(shader_type, dynamic_cast(context), settings); } -ShaderMT::ShaderMT(Shader::Type shader_type, ContextMT& context, const Settings& settings) +ShaderMT::ShaderMT(Shader::Type shader_type, ContextBase& context, const Settings& settings) : ShaderBase(shader_type, context, settings) - , m_mtl_function([context.GetLibraryMT(settings.entry_function.file_name)->Get() newFunctionWithName: Methane::MacOS::ConvertToNSType(GetCompiledEntryFunctionName())]) + , m_mtl_function([context.GetLibraryMT(settings.entry_function.file_name)->Get() newFunctionWithName: Methane::MacOS::ConvertToNsType(GetCompiledEntryFunctionName())]) { ITT_FUNCTION_TASK(); @@ -167,14 +117,13 @@ static MTLVertexStepFunction GetVertexStepFunction(StepType step_type) noexcept [m_mtl_function release]; } -ShaderBase::ResourceBindings ShaderMT::GetResourceBindings(const std::set& constant_argument_names, - const std::set& addressable_argument_names) const +ShaderBase::ArgumentBindings ShaderMT::GetArgumentBindings(const Program::ArgumentDescriptions& argument_descriptions) const { ITT_FUNCTION_TASK(); - ShaderBase::ResourceBindings resource_bindings; + ArgumentBindings argument_bindings; if (m_mtl_arguments == nil) - return resource_bindings; + return argument_bindings; #ifndef NDEBUG NSLog(@"%s shader '%s' arguments:", GetTypeName().c_str(), GetCompiledEntryFunctionName().c_str()); @@ -182,30 +131,30 @@ static MTLVertexStepFunction GetVertexStepFunction(StepType step_type) noexcept for(MTLArgument* mtl_arg in m_mtl_arguments) { - if (mtl_arg.active == NO) + if (!mtl_arg.active) continue; - const std::string argument_name = Methane::MacOS::ConvertFromNSType(mtl_arg.name); + std::string argument_name = Methane::MacOS::ConvertFromNsType(mtl_arg.name); if (argument_name.find("vertexBuffer.") == 0) { // Skip input vertex buffers, since they are set with a separate RenderCommandList call, not through resource bindings continue; } - const bool is_constant_binding = constant_argument_names.find(argument_name) != constant_argument_names.end(); - const bool is_addressable_binding = addressable_argument_names.find(argument_name) != addressable_argument_names.end(); + const Program::Argument shader_argument(GetType(), argument_name); + const auto argument_desc_it = Program::FindArgumentDescription(argument_descriptions, shader_argument); + const Program::ArgumentDesc argument_desc = argument_desc_it == argument_descriptions.end() + ? Program::ArgumentDesc(shader_argument) + : *argument_desc_it; - resource_bindings.push_back(std::make_shared( - m_context, - ResourceBindingMT::Settings + argument_bindings.emplace_back(std::make_shared( + GetContext(), + ProgramBindingsMT::ArgumentBindingMT::SettingsMT { { - m_type, - argument_name, + argument_desc, GetResourceTypeByMetalArgumentType(mtl_arg.type), static_cast(mtl_arg.arrayLength), - is_constant_binding, - is_addressable_binding }, static_cast(mtl_arg.index) } @@ -225,12 +174,15 @@ static MTLVertexStepFunction GetVertexStepFunction(StepType step_type) noexcept #endif } - return resource_bindings; + return argument_bindings; } MTLVertexDescriptor* ShaderMT::GetNativeVertexDescriptor(const ProgramMT& program) const { ITT_FUNCTION_TASK(); + + // Regex matching prefix of the input attributes "in_var_" + static const std::regex s_attr_suffix_regex("^in_var_"); MTLVertexDescriptor* mtl_vertex_desc = [[MTLVertexDescriptor alloc] init]; [mtl_vertex_desc reset]; @@ -238,13 +190,13 @@ static MTLVertexStepFunction GetVertexStepFunction(StepType step_type) noexcept std::vector input_buffer_byte_offsets; for(MTLVertexAttribute* mtl_vertex_attrib in m_mtl_function.vertexAttributes) { - if (mtl_vertex_attrib.active == NO) + if (!mtl_vertex_attrib.active) continue; const MTLVertexFormat mtl_vertex_format = TypeConverterMT::MetalDataTypeToVertexFormat(mtl_vertex_attrib.attributeType); - const std::string attrib_name = Methane::MacOS::ConvertFromNSType(mtl_vertex_attrib.name); + const std::string attrib_name = std::regex_replace(Methane::MacOS::ConvertFromNsType(mtl_vertex_attrib.name), s_attr_suffix_regex, ""); const uint32_t attrib_size = TypeConverterMT::ByteSizeOfVertexFormat(mtl_vertex_format); - const uint32_t attrib_slot = GetProgramInputBufferIndexByArgumentName(program, attrib_name); + const uint32_t attrib_slot = GetProgramInputBufferIndexByArgumentSemantic(program, attrib_name); if (attrib_slot <= input_buffer_byte_offsets.size()) input_buffer_byte_offsets.resize(attrib_slot + 1, 0); @@ -273,10 +225,10 @@ static MTLVertexStepFunction GetVertexStepFunction(StepType step_type) noexcept return mtl_vertex_desc; } -ContextMT& ShaderMT::GetContextMT() noexcept +IContextMT& ShaderMT::GetContextMT() noexcept { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(GetContext()); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/TextureMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/TextureMT.hh index b6c40c8da..617558afa 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/TextureMT.hh +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/TextureMT.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -31,11 +31,11 @@ Metal implementation of the texture interface. namespace Methane::Graphics { -class TextureMT : public TextureBase +class RenderContextMT; + +class TextureMT final : public TextureBase { public: - using Ptr = std::shared_ptr; - TextureMT(ContextBase& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); ~TextureMT() override; @@ -50,8 +50,9 @@ public: const id& GetNativeTexture() const { return m_mtl_texture; } -protected: +private: void GenerateMipLevels(); + RenderContextMT& GetRenderContextMT(); MTLTextureUsage GetNativeTextureUsage(); MTLTextureDescriptor* GetNativeTextureDescriptor(); diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/TextureMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/TextureMT.mm index 4f8640f5e..416a69086 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/TextureMT.mm +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/TextureMT.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,12 +22,11 @@ ******************************************************************************/ #include "TextureMT.hh" -#include "ContextMT.hh" -#include "DeviceMT.hh" -#include "RenderCommandListMT.hh" +#include "RenderContextMT.hh" +#include "BlitCommandListMT.hh" #include "TypesMT.hh" -#include +#include #include #include @@ -51,7 +50,6 @@ static MTLTextureType GetNativeTextureType(Texture::DimensionType dimension_type case Texture::DimensionType::CubeArray: return MTLTextureTypeCubeArray; case Texture::DimensionType::Tex3D: return MTLTextureType3D; // TODO: add support for MTLTextureTypeTextureBuffer - default: throw std::invalid_argument("Dimension type is not supported in Metal"); } } @@ -71,52 +69,50 @@ static MTLRegion GetTextureRegion(const Dimensions& dimensions, Texture::Dimensi return MTLRegionMake2D(0, 0, dimensions.width, dimensions.height); case Texture::DimensionType::Tex3D: return MTLRegionMake3D(0, 0, 0, dimensions.width, dimensions.height, dimensions.depth); - default: - throw std::invalid_argument("Dimension type is not supported in Metal"); } return {}; } -Texture::Ptr Texture::CreateRenderTarget(Context& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage) +Ptr Texture::CreateRenderTarget(RenderContext& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context), settings, descriptor_by_usage); + return std::make_shared(dynamic_cast(context), settings, descriptor_by_usage); } -Texture::Ptr Texture::CreateFrameBuffer(Context& context, uint32_t /*frame_buffer_index*/, const DescriptorByUsage& descriptor_by_usage) +Ptr Texture::CreateFrameBuffer(RenderContext& context, uint32_t /*frame_buffer_index*/, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); - const Context::Settings& context_settings = context.GetSettings(); + const RenderContext::Settings& context_settings = context.GetSettings(); const Settings texture_settings = Settings::FrameBuffer(context_settings.frame_size, context_settings.color_format); - return std::make_shared(static_cast(context), texture_settings, descriptor_by_usage); + return std::make_shared(dynamic_cast(context), texture_settings, descriptor_by_usage); } -Texture::Ptr Texture::CreateDepthStencilBuffer(Context& context, const DescriptorByUsage& descriptor_by_usage) +Ptr Texture::CreateDepthStencilBuffer(RenderContext& context, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); - const Context::Settings& context_settings = context.GetSettings(); + const RenderContext::Settings& context_settings = context.GetSettings(); const Settings texture_settings = Settings::DepthStencilBuffer(context_settings.frame_size, context_settings.depth_stencil_format); - return std::make_shared(static_cast(context), texture_settings, descriptor_by_usage); + return std::make_shared(dynamic_cast(context), texture_settings, descriptor_by_usage); } -Texture::Ptr Texture::CreateImage(Context& context, const Dimensions& dimensions, uint32_t array_length, PixelFormat pixel_format, bool mipmapped, const DescriptorByUsage& descriptor_by_usage) +Ptr Texture::CreateImage(Context& context, const Dimensions& dimensions, uint32_t array_length, PixelFormat pixel_format, bool mipmapped, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); const Settings texture_settings = Settings::Image(dimensions, array_length, pixel_format, mipmapped, Usage::ShaderRead); - return std::make_shared(static_cast(context), texture_settings, descriptor_by_usage); + return std::make_shared(dynamic_cast(context), texture_settings, descriptor_by_usage); } -Texture::Ptr Texture::CreateCube(Context& context, uint32_t dimension_size, uint32_t array_length, PixelFormat pixel_format, bool mipmapped, const DescriptorByUsage& descriptor_by_usage) +Ptr Texture::CreateCube(Context& context, uint32_t dimension_size, uint32_t array_length, PixelFormat pixel_format, bool mipmapped, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); const Settings texture_settings = Settings::Cube(dimension_size, array_length, pixel_format, mipmapped, Usage::ShaderRead); - return std::make_shared(static_cast(context), texture_settings, descriptor_by_usage); + return std::make_shared(dynamic_cast(context), texture_settings, descriptor_by_usage); } TextureMT::TextureMT(ContextBase& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage) : TextureBase(context, settings, descriptor_by_usage) , m_mtl_texture(settings.type == Texture::Type::FrameBuffer - ? [GetContextMT().GetNativeDrawable() texture] + ? [GetRenderContextMT().GetNativeDrawable() texture] : [GetContextMT().GetDeviceMT().GetNativeDevice() newTextureWithDescriptor:GetNativeTextureDescriptor()]) { ITT_FUNCTION_TASK(); @@ -128,9 +124,9 @@ static MTLRegion GetTextureRegion(const Dimensions& dimensions, Texture::Dimensi { ITT_FUNCTION_TASK(); - if (m_settings.type != Texture::Type::FrameBuffer) + if (TextureBase::GetSettings().type != Texture::Type::FrameBuffer) { - m_context.GetResourceManager().GetReleasePool().AddResource(*this); + GetContext().GetResourceManager().GetReleasePool().AddResource(*this); } } @@ -140,7 +136,7 @@ static MTLRegion GetTextureRegion(const Dimensions& dimensions, Texture::Dimensi TextureBase::SetName(name); - m_mtl_texture.label = MacOS::ConvertToNSType(name); + m_mtl_texture.label = MacOS::ConvertToNsType(name); } void TextureMT::SetData(const SubResources& sub_resources) @@ -152,39 +148,40 @@ static MTLRegion GetTextureRegion(const Dimensions& dimensions, Texture::Dimensi { throw std::invalid_argument("Can not set texture data from empty sub-resources."); } - - const uint32_t bytes_per_row = m_settings.dimensions.width * GetPixelSize(m_settings.pixel_format); - const uint32_t bytes_per_image = m_settings.dimensions.height * bytes_per_row; - const MTLRegion texture_region = GetTextureRegion(m_settings.dimensions, m_settings.dimension_type); - for(const SubResource& sub_resourse : sub_resources) + const Settings& settings = GetSettings(); + const uint32_t bytes_per_row = settings.dimensions.width * GetPixelSize(settings.pixel_format); + const uint32_t bytes_per_image = settings.dimensions.height * bytes_per_row; + const MTLRegion texture_region = GetTextureRegion(settings.dimensions, settings.dimension_type); + + for(const SubResource& sub_resource : sub_resources) { uint32_t slice = 0; - switch(m_settings.dimension_type) + switch(settings.dimension_type) { case Texture::DimensionType::Tex1DArray: case Texture::DimensionType::Tex2DArray: - slice = sub_resourse.index.array_index; + slice = sub_resource.index.array_index; break; case Texture::DimensionType::Cube: - slice = sub_resourse.index.depth_slice; + slice = sub_resource.index.depth_slice; break; case Texture::DimensionType::CubeArray: - slice = sub_resourse.index.depth_slice + sub_resourse.index.array_index * 6; + slice = sub_resource.index.depth_slice + sub_resource.index.array_index * 6; break; default: slice = 0; } [m_mtl_texture replaceRegion:texture_region - mipmapLevel:sub_resourse.index.mip_level + mipmapLevel:sub_resource.index.mip_level slice:slice - withBytes:sub_resourse.p_data + withBytes:sub_resource.p_data bytesPerRow:bytes_per_row bytesPerImage:bytes_per_image]; } - if (m_settings.mipmapped && sub_resources.size() < GetRequiredSubresourceCount()) + if (settings.mipmapped && sub_resources.size() < GetRequiredSubresourceCount()) { GenerateMipLevels(); } @@ -200,12 +197,12 @@ static MTLRegion GetTextureRegion(const Dimensions& dimensions, Texture::Dimensi { ITT_FUNCTION_TASK(); - if (m_settings.type != Texture::Type::FrameBuffer) + if (GetSettings().type != Texture::Type::FrameBuffer) { throw std::logic_error("Unable to update frame buffer on non-FB texture."); } - m_mtl_texture = [GetContextMT().GetNativeDrawable() texture]; + m_mtl_texture = [GetRenderContextMT().GetNativeDrawable() texture]; } MTLTextureUsage TextureMT::GetNativeTextureUsage() @@ -213,14 +210,15 @@ static MTLRegion GetTextureRegion(const Dimensions& dimensions, Texture::Dimensi ITT_FUNCTION_TASK(); NSUInteger texture_usage = MTLTextureUsageUnknown; + const Settings& settings = GetSettings(); - if (m_settings.usage_mask & static_cast(TextureBase::Usage::ShaderRead)) + if (settings.usage_mask & static_cast(TextureBase::Usage::ShaderRead)) texture_usage |= MTLTextureUsageShaderRead; - if (m_settings.usage_mask & static_cast(TextureBase::Usage::ShaderWrite)) + if (settings.usage_mask & static_cast(TextureBase::Usage::ShaderWrite)) texture_usage |= MTLTextureUsageShaderWrite; - if (m_settings.usage_mask & static_cast(TextureBase::Usage::RenderTarget)) + if (settings.usage_mask & static_cast(TextureBase::Usage::RenderTarget)) texture_usage |= MTLTextureUsageRenderTarget; return texture_usage; @@ -230,22 +228,23 @@ static MTLRegion GetTextureRegion(const Dimensions& dimensions, Texture::Dimensi { ITT_FUNCTION_TASK(); - const MTLPixelFormat mtl_pixel_format = TypeConverterMT::DataFormatToMetalPixelType(m_settings.pixel_format); - const BOOL is_tex_mipmapped = MacOS::ConvertToNSType(m_settings.mipmapped); + const Settings& settings = GetSettings(); + const MTLPixelFormat mtl_pixel_format = TypeConverterMT::DataFormatToMetalPixelType(settings.pixel_format); + const BOOL is_tex_mipmapped = MacOS::ConvertToNsType(settings.mipmapped); MTLTextureDescriptor* mtl_tex_desc = nil; - switch(m_settings.dimension_type) + switch(settings.dimension_type) { case Texture::DimensionType::Tex2D: mtl_tex_desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:mtl_pixel_format - width:m_settings.dimensions.width - height:m_settings.dimensions.height + width:settings.dimensions.width + height:settings.dimensions.height mipmapped:is_tex_mipmapped]; break; case Texture::DimensionType::Cube: mtl_tex_desc = [MTLTextureDescriptor textureCubeDescriptorWithPixelFormat:mtl_pixel_format - size:m_settings.dimensions.width + size:settings.dimensions.width mipmapped:is_tex_mipmapped]; break; @@ -257,22 +256,19 @@ static MTLRegion GetTextureRegion(const Dimensions& dimensions, Texture::Dimensi case Texture::DimensionType::Tex3D: mtl_tex_desc = [[MTLTextureDescriptor alloc] init]; mtl_tex_desc.pixelFormat = mtl_pixel_format; - mtl_tex_desc.textureType = GetNativeTextureType(m_settings.dimension_type); - mtl_tex_desc.width = m_settings.dimensions.width; - mtl_tex_desc.height = m_settings.dimensions.height; - mtl_tex_desc.depth = m_settings.dimensions.depth; - mtl_tex_desc.arrayLength = m_settings.array_length; + mtl_tex_desc.textureType = GetNativeTextureType(settings.dimension_type); + mtl_tex_desc.width = settings.dimensions.width; + mtl_tex_desc.height = settings.dimensions.height; + mtl_tex_desc.depth = settings.dimensions.depth; + mtl_tex_desc.arrayLength = settings.array_length; mtl_tex_desc.mipmapLevelCount = GetMipLevelsCount(); break; - - default: - throw std::logic_error("Unsupported texture dimension type in Metal"); } if (!mtl_tex_desc) return nil; - if (!m_settings.cpu_accessible) + if (!settings.cpu_accessible) { mtl_tex_desc.resourceOptions = MTLResourceStorageModePrivate; } @@ -285,16 +281,22 @@ static MTLRegion GetTextureRegion(const Dimensions& dimensions, Texture::Dimensi { ITT_FUNCTION_TASK(); - RenderCommandListMT& render_command_list = static_cast(m_context.GetUploadCommandList()); - render_command_list.StartBlitEncoding(); + BlitCommandListMT& blit_command_list = static_cast(GetContext().GetUploadCommandList()); + blit_command_list.Reset("Texture MIPs Generation"); - id& mtl_blit_encoder = render_command_list.GetNativeBlitEncoder(); + id& mtl_blit_encoder = blit_command_list.GetNativeBlitEncoder(); assert(mtl_blit_encoder != nil); assert(m_mtl_texture != nil); [mtl_blit_encoder generateMipmapsForTexture: m_mtl_texture]; - - render_command_list.EndBlitEncoding(); +} + +RenderContextMT& TextureMT::GetRenderContextMT() +{ + ITT_FUNCTION_TASK(); + if (GetContext().GetType() != Context::Type::Render) + throw std::runtime_error("Incompatible context type."); + return static_cast(GetContextMT()); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/TypesMT.hh b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/TypesMT.hh index 7faaacaf7..1cea60fc1 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/TypesMT.hh +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/TypesMT.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ limitations under the License. ******************************************************************************* FILE: Methane/Graphics/Metal/TypesMT.hh -Methane graphics types convertors to Metal native types. +Methane graphics types converters to Metal native types. ******************************************************************************/ diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/TypesMT.mm b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/TypesMT.mm index 0dc9faea3..440aa87b3 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/TypesMT.mm +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Metal/TypesMT.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,13 +17,13 @@ ******************************************************************************* FILE: Methane/Graphics/Metal/TypesMT.mm -Methane graphics types convertors to Metal native types. +Methane graphics types converters to Metal native types. ******************************************************************************/ #include "TypesMT.hh" -#include +#include #include @@ -118,7 +118,6 @@ // MTLPixelFormatDepth32Float_Stencil8; // MTLPixelFormatX32_Stencil8; // MTLPixelFormatX24_Stencil8; - default: assert(0); } return MTLPixelFormatInvalid; } @@ -264,7 +263,7 @@ MTLClearColor TypeConverterMT::ColorToMetalClearColor(const Color4f& color) noexcept { ITT_FUNCTION_TASK(); - return MTLClearColorMake(color.r(), color.g(), color.b(), color.a()); + return MTLClearColorMake(color.GetR(), color.GetG(), color.GetB(), color.GetA()); } NSRect TypeConverterMT::RectToNS(const FrameRect& rect) noexcept @@ -276,7 +275,7 @@ NSRect TypeConverterMT::CreateNSRect(const FrameSize& size, const Point2i& origin) noexcept { ITT_FUNCTION_TASK(); - return NSMakeRect(origin.x(), origin.y(), size.width, size.height); + return NSMakeRect(origin.GetX(), origin.GetY(), size.width, size.height); } FrameRect TypeConverterMT::RectFromNS(const NSRect& rect) noexcept @@ -301,7 +300,6 @@ case Compare::GreaterEqual: return MTLCompareFunctionGreaterEqual; case Compare::Equal: return MTLCompareFunctionEqual; case Compare::NotEqual: return MTLCompareFunctionNotEqual; - default: assert(0); } return MTLCompareFunctionNever; } diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/BufferNT.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/BufferNT.h index 9dc552068..4e3961e54 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/BufferNT.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/BufferNT.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/CommandQueueNT.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/CommandQueueNT.h index aa5914deb..68cf07d68 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/CommandQueueNT.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/CommandQueueNT.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/ContextNT.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/ContextNT.h index c14ef1472..9755d72e1 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/ContextNT.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/ContextNT.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ Native implementation alias of the context interface. #elif defined __APPLE__ -#include +#include #elif defined __linux__ @@ -42,15 +42,15 @@ namespace Methane::Graphics #if defined _WIN32 -using ContextNT = ContextDX; +using IContextNT = IContextDX; #elif defined __APPLE__ -using ContextNT = ContextMT; +using IContextNT = IContextMT; #elif defined __linux__ -using ContextNT = ContextVK; +using IContextNT = IContextVK; #endif diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/DescriptorHeapNT.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/DescriptorHeapNT.h index 413813abd..15861f64c 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/DescriptorHeapNT.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/DescriptorHeapNT.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/ProgramNT.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/ProgramNT.h index f21a34abc..3a6e0d216 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/ProgramNT.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/ProgramNT.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/RenderCommandListNT.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/RenderCommandListNT.h index 73b9be5b0..d67e5ace7 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/RenderCommandListNT.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/RenderCommandListNT.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/RenderContextNT.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/RenderContextNT.h new file mode 100644 index 000000000..ae1338e13 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/RenderContextNT.h @@ -0,0 +1,57 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Native/ContextNT.h +Native implementation alias of the context interface. + +******************************************************************************/ + +#pragma once + +#if defined _WIN32 + +#include + +#elif defined __APPLE__ + +#include + +#elif defined __linux__ + +#include + +#endif + +namespace Methane::Graphics +{ + +#if defined _WIN32 + +using RenderContextNT = RenderContextDX; + +#elif defined __APPLE__ + +using RenderContextNT = RenderContextMT; + +#elif defined __linux__ + +using RenderContextNT = RenderContextVK; + +#endif + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/RenderPassNT.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/RenderPassNT.h index fe2652544..04a2773f8 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/RenderPassNT.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/RenderPassNT.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/RenderStateNT.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/RenderStateNT.h index e7c2e8468..be3d88972 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/RenderStateNT.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/RenderStateNT.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/ResourceNT.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/ResourceNT.h index 1497580bf..6d0285f50 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/ResourceNT.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/ResourceNT.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/SamplerNT.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/SamplerNT.h index ed6fc82fb..eb863127b 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/SamplerNT.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/SamplerNT.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/ShaderNT.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/ShaderNT.h index f460c4d51..7a826a593 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/ShaderNT.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/ShaderNT.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/TextureNT.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/TextureNT.h index 7fbbda7bb..305790773 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Native/TextureNT.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Native/TextureNT.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/ObjectBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/ObjectBase.h index c42e14ce9..d5f084c2e 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/ObjectBase.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/ObjectBase.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/ParallelRenderCommandListBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/ParallelRenderCommandListBase.cpp index 4ed19ee1c..851a56950 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/ParallelRenderCommandListBase.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/ParallelRenderCommandListBase.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ Base implementation of the parallel render command list interface. #include "BufferBase.h" #include "ProgramBase.h" -#include +#include #include #include @@ -42,57 +42,65 @@ inline std::string GetThreadCommandListName(const std::string& name, uint32_t in } ParallelRenderCommandListBase::ParallelRenderCommandListBase(CommandQueueBase& command_queue, RenderPassBase& pass) - : CommandListBase(command_queue, Type::ParallelRenderCommandList) + : CommandListBase(command_queue, Type::ParallelRender) , m_sp_pass(pass.GetPtr()) { ITT_FUNCTION_TASK(); } -void ParallelRenderCommandListBase::Reset(const RenderState::Ptr& sp_render_state, const std::string& debug_group) +void ParallelRenderCommandListBase::Reset(const Ptr& sp_render_state, const std::string& debug_group) { ITT_FUNCTION_TASK(); - - uint32_t render_command_list_index = 0; - for(const RenderCommandList::Ptr& sp_render_command_list : m_parallel_comand_lists) + // Per-thread render command lists can be reset in parallel only with DirectX 12 on Windows +#ifdef _WIN32 + Data::ParallelFor(0, m_parallel_command_lists.size(), + [this, &sp_render_state, &debug_group](size_t render_command_list_index) +#else + for(size_t render_command_list_index = 0u; render_command_list_index < m_parallel_command_lists.size(); ++render_command_list_index) +#endif { + const Ptr& sp_render_command_list = m_parallel_command_lists[render_command_list_index]; assert(sp_render_command_list); - const std::string render_debug_group = GetThreadCommandListName(debug_group, render_command_list_index++); + const std::string render_debug_group = GetThreadCommandListName(debug_group, static_cast(render_command_list_index)); sp_render_command_list->Reset(sp_render_state, render_debug_group); } +#ifdef _WIN32 + ); +#endif } -void ParallelRenderCommandListBase::Commit(bool present_drawable) +void ParallelRenderCommandListBase::Commit() { ITT_FUNCTION_TASK(); - for(const RenderCommandList::Ptr& sp_render_command_list : m_parallel_comand_lists) + for(const Ptr& sp_render_command_list : m_parallel_command_lists) { assert(!!sp_render_command_list); - sp_render_command_list->Commit(false); + sp_render_command_list->Commit(); } - CommandListBase::Commit(present_drawable); + CommandListBase::Commit(); } void ParallelRenderCommandListBase::SetParallelCommandListsCount(uint32_t count) { ITT_FUNCTION_TASK(); - uint32_t initial_count = static_cast(m_parallel_comand_lists.size()); + uint32_t initial_count = static_cast(m_parallel_command_lists.size()); if (count < initial_count) { - m_parallel_comand_lists.resize(count); + m_parallel_command_lists.resize(count); return; } const std::string& name = GetName(); - m_parallel_comand_lists.reserve(count); + m_parallel_command_lists.reserve(count); for(uint32_t cmd_list_index = initial_count; cmd_list_index < count; ++cmd_list_index) { - m_parallel_comand_lists.emplace_back(RenderCommandList::Create(*this)); + m_parallel_command_lists.emplace_back(RenderCommandList::Create(*this)); if (!name.empty()) { - m_parallel_comand_lists.back()->SetName(GetThreadCommandListName(name, cmd_list_index)); + m_parallel_command_lists.back()->SetName(GetThreadCommandListName(name, cmd_list_index)); } } } @@ -101,7 +109,7 @@ void ParallelRenderCommandListBase::Execute(uint32_t frame_index) { ITT_FUNCTION_TASK(); - for(const RenderCommandList::Ptr& sp_render_command_list : m_parallel_comand_lists) + for(const Ptr& sp_render_command_list : m_parallel_command_lists) { assert(!!sp_render_command_list); RenderCommandListBase& metal_render_command_list = static_cast(*sp_render_command_list); @@ -115,7 +123,7 @@ void ParallelRenderCommandListBase::Complete(uint32_t frame_index) { ITT_FUNCTION_TASK(); - for(const RenderCommandList::Ptr& sp_render_command_list : m_parallel_comand_lists) + for(const Ptr& sp_render_command_list : m_parallel_command_lists) { assert(!!sp_render_command_list); RenderCommandListBase& metal_render_command_list = static_cast(*sp_render_command_list); @@ -135,7 +143,7 @@ void ParallelRenderCommandListBase::SetName(const std::string& name) return; uint32_t render_cmd_list_index = 0; - for(const RenderCommandList::Ptr& sp_render_cmd_list : m_parallel_comand_lists) + for(const Ptr& sp_render_cmd_list : m_parallel_command_lists) { assert(!!sp_render_cmd_list); sp_render_cmd_list->SetName(GetThreadCommandListName(name, render_cmd_list_index)); diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/ParallelRenderCommandListBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/ParallelRenderCommandListBase.h index 81c845ccc..5fd62a684 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/ParallelRenderCommandListBase.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/ParallelRenderCommandListBase.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -40,34 +40,33 @@ class ParallelRenderCommandListBase , public CommandListBase { public: - using Ptr = std::shared_ptr; - using WeakPtr = std::weak_ptr; - ParallelRenderCommandListBase(CommandQueueBase& command_queue, RenderPassBase& render_pass); + + using CommandListBase::Reset; // ParallelRenderCommandList interface - void Reset(const RenderState::Ptr& sp_render_state, const std::string& debug_group = "") override; + void Reset(const Ptr& sp_render_state, const std::string& debug_group = "") override; void SetParallelCommandListsCount(uint32_t count) override; - const RenderCommandList::Ptrs& GetParallelCommandLists() const override { return m_parallel_comand_lists; } + const Ptrs& GetParallelCommandLists() const override { return m_parallel_command_lists; } // CommandListBase interface - void SetResourceBarriers(const ResourceBase::Barriers&) override { } + void SetResourceBarriers(const ResourceBase::Barriers&) override { throw std::logic_error("Can not set resource barriers on parallel render command list."); } void Execute(uint32_t frame_index) override; void Complete(uint32_t frame_index) override; // CommandList interface - void PushDebugGroup(const std::string& name) override { throw std::logic_error("Not available for parallel render command list."); } - void PopDebugGroup() override { throw std::logic_error("Not available for parallel render command list."); } - void Commit(bool present_drawable) override; + void PushDebugGroup(const std::string& name) override { throw std::logic_error("Can no use debug groups on parallel render command list."); } + void PopDebugGroup() override { throw std::logic_error("Can no use debug groups on parallel render command list."); } + void Commit() override; // Object interface void SetName(const std::string& name) override; RenderPassBase& GetPass(); -protected: - const RenderPass::Ptr m_sp_pass; - RenderCommandList::Ptrs m_parallel_comand_lists; +private: + const Ptr m_sp_pass; + Ptrs m_parallel_command_lists; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/ProgramBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/ProgramBase.cpp index ade8f919f..5308fcaac 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/ProgramBase.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/ProgramBase.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,13 +23,11 @@ Base implementation of the program interface. #include "ProgramBase.h" #include "ContextBase.h" -#include "ResourceManager.h" -#include +#include #include #include -#include namespace Methane::Graphics { @@ -38,8 +36,8 @@ static const std::hash g_argument_name_hash; Program::Argument::Argument(Shader::Type shader_type, std::string argument_name) : shader_type(shader_type) - , argument_name(std::move(argument_name)) - , hash(g_argument_name_hash(argument_name) ^ (static_cast(shader_type) << 1)) + , name(std::move(argument_name)) + , hash(g_argument_name_hash(name) ^ (static_cast(shader_type) << 1)) { ITT_FUNCTION_TASK(); } @@ -47,243 +45,42 @@ Program::Argument::Argument(Shader::Type shader_type, std::string argument_name) bool Program::Argument::operator==(const Argument& other) const { ITT_FUNCTION_TASK(); - return std::tie(hash, shader_type, argument_name) == - std::tie(other.hash, other.shader_type, other.argument_name); + return std::tie(hash, shader_type, name) == + std::tie(other.hash, other.shader_type, other.name); } -ProgramBase::ResourceBindingsBase::ResourceBindingsBase(const Program::Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument) - : m_sp_program(sp_program) +Program::ArgumentDesc::ArgumentDesc(Shader::Type shader_type, std::string argument_name, Modifiers::Mask modifiers) + : Argument(shader_type, argument_name) + , modifiers(modifiers) { ITT_FUNCTION_TASK(); - - if (!m_sp_program) - { - throw std::runtime_error("Can not create resource bindings for an empty program."); - } - - ReserveDescriptorHeapRanges(); - SetResourcesForArguments(resource_locations_by_argument); - VerifyAllArgumentsAreBoundToResources(); } -ProgramBase::ResourceBindingsBase::ResourceBindingsBase(const ResourceBindingsBase& other_resource_bingings, const ResourceLocationsByArgument& replace_resource_locations_by_argument) - : m_sp_program(other_resource_bingings.m_sp_program) - , m_descriptor_heap_reservations_by_type(other_resource_bingings.m_descriptor_heap_reservations_by_type) +Program::ArgumentDesc::ArgumentDesc(const Argument& argument, Modifiers::Mask modifiers) + : Argument(argument) + , modifiers(modifiers) { ITT_FUNCTION_TASK(); - - // Form map of volatile resource bindings with replaced resource locations - ResourceLocationsByArgument resource_locations_by_argument = replace_resource_locations_by_argument; - for (const auto& argument_and_resource_binding : other_resource_bingings.m_resource_binding_by_argument) - { - // NOTE: constant resource bindings are reusing single binding-object for the whole program, - // so there's no need in setting its value, since it was already set by the original resource binding - if (argument_and_resource_binding.second->IsConstant() || - resource_locations_by_argument.count(argument_and_resource_binding.first)) - continue; - - resource_locations_by_argument.emplace( - argument_and_resource_binding.first, - argument_and_resource_binding.second->GetResourceLocations() - ); - } - - ReserveDescriptorHeapRanges(); - SetResourcesForArguments(resource_locations_by_argument); - VerifyAllArgumentsAreBoundToResources(); } -ProgramBase::ResourceBindingsBase::~ResourceBindingsBase() +Program::ArgumentDescriptions::const_iterator Program::FindArgumentDescription(const ArgumentDescriptions& argument_descriptions, const Argument& argument) { ITT_FUNCTION_TASK(); - // Release mutable descriptor ranges in heaps (constant ranges are released by the program) - for (const auto& descriptor_type_and_heap_reservation : m_descriptor_heap_reservations_by_type) - { - if (!descriptor_type_and_heap_reservation) - continue; + Program::ArgumentDescriptions::const_iterator argument_desc_it = argument_descriptions.find(argument); + if (argument_desc_it != argument_descriptions.end()) + return argument_desc_it; - const DescriptorHeap::Reservation& heap_reservation = *descriptor_type_and_heap_reservation; - if (heap_reservation.mutable_range.IsEmpty()) - continue; - - heap_reservation.heap.get().ReleaseRange(heap_reservation.mutable_range); - } + const Argument all_shaders_argument(Shader::Type::All, argument.name); + return argument_descriptions.find(all_shaders_argument); } -void ProgramBase::ResourceBindingsBase::ReserveDescriptorHeapRanges() -{ - ITT_FUNCTION_TASK(); - - struct DescriptorsCount - { - uint32_t constant_count = 0; - uint32_t mutable_count = 0; - }; - - assert(!!m_sp_program); - ProgramBase& program = static_cast(*m_sp_program); - - // Count the number of constant and mutable discriptots to be allocated in each desriptor heap - std::map descriptors_count_by_heap_type; - for (const auto& resource_binding_by_argument : program.m_resource_binding_by_argument) - { - if (!resource_binding_by_argument.second) - { - throw std::runtime_error("No resource binding is set for an argument \"" + resource_binding_by_argument.first.argument_name + "\" of shader."); - } - - const Shader::ResourceBinding& resource_binding = *resource_binding_by_argument.second; - m_arguments.insert(resource_binding_by_argument.first); - - auto resource_binding_by_argument_it = m_resource_binding_by_argument.find(resource_binding_by_argument.first); - if (resource_binding_by_argument_it == m_resource_binding_by_argument.end()) - { - m_resource_binding_by_argument.emplace( - resource_binding_by_argument.first, - resource_binding.IsConstant() - ? resource_binding_by_argument.second - : Shader::ResourceBinding::CreateCopy(resource_binding) - ); - } - else if (!resource_binding.IsConstant()) - { - resource_binding_by_argument_it->second = Shader::ResourceBinding::CreateCopy(*resource_binding_by_argument_it->second); - } - - // NOTE: addressable resource bindings do not require descriptors to be created, instead they use direct GPU memory offset from resource - if (resource_binding.IsAddressable()) - continue; - - const DescriptorHeap::Type heap_type = static_cast(resource_binding).GetDescriptorHeapType(); - DescriptorsCount& descriptors = descriptors_count_by_heap_type[heap_type]; - if (resource_binding.IsConstant()) - { - descriptors.constant_count += resource_binding.GetResourceCount(); - } - else - { - descriptors.mutable_count += resource_binding.GetResourceCount(); - } - } - - // Reserve descriptor ranges in heaps for resource bindings state - ResourceManager& resource_manager = program.GetContext().GetResourceManager(); - for (const auto& descriptor_heap_type_and_count : descriptors_count_by_heap_type) - { - const DescriptorHeap::Type heap_type = descriptor_heap_type_and_count.first; - const DescriptorsCount& descriptors = descriptor_heap_type_and_count.second; - - std::optional& descriptor_heap_reservation_opt = m_descriptor_heap_reservations_by_type[static_cast(heap_type)]; - if (!descriptor_heap_reservation_opt) - { - descriptor_heap_reservation_opt.emplace( - resource_manager.GetDefaultShaderVisibleDescriptorHeap(heap_type), - DescriptorHeap::Range(0, 0), - DescriptorHeap::Range(0, 0) - ); - } - - DescriptorHeap::Reservation& heap_reservation = *descriptor_heap_reservation_opt; - if (descriptors.constant_count > 0) - { - heap_reservation.constant_range = static_cast(*m_sp_program).ReserveConstantDescriptorRange(heap_reservation.heap.get(), descriptors.constant_count); - } - if (descriptors.mutable_count > 0) - { - DescriptorHeap::RangePtr sp_mutable_heap_range = heap_reservation.heap.get().ReserveRange(descriptors.mutable_count); - if (!sp_mutable_heap_range) - { - throw std::runtime_error("Failed to reserve mutable descriptor heap range. Descriptor heap is not big enough."); - } - heap_reservation.mutable_range = *sp_mutable_heap_range; - } - } -} - -void ProgramBase::ResourceBindingsBase::SetResourcesForArguments(const ResourceLocationsByArgument& resource_locations_by_argument) -{ - ITT_FUNCTION_TASK(); - - for (const auto& argument_and_resource_locations : resource_locations_by_argument) - { - const Program::Argument argument = argument_and_resource_locations.first; - const Shader::ResourceBinding::Ptr& sp_binding = Get(argument); - if (!sp_binding) - { -#ifndef PROGRAM_IGNORE_MISSING_ARGUMENTS - const Argument all_shaders_argument(Shader::Type::All, argument.argument_name); - const bool all_shaders_argument_found = !!Get(all_shaders_argument); - throw std::runtime_error("Program \"" + m_sp_program->GetName() + - "\" does not have argument \"" + argument.argument_name + - "\" of " + Shader::GetTypeName(argument.shader_type) + " shader." + - (all_shaders_argument_found ? " Instead this argument is used in All shaders." : "") ); -#else - continue; -#endif - } - sp_binding->SetResourceLocations(argument_and_resource_locations.second); - } -} - -const Shader::ResourceBinding::Ptr& ProgramBase::ResourceBindingsBase::Get(const Argument& shader_argument) const -{ - ITT_FUNCTION_TASK(); - - static const Shader::ResourceBinding::Ptr sp_empty_resource_binding; - auto resource_binding_by_argument_it = m_resource_binding_by_argument.find(shader_argument); - return resource_binding_by_argument_it != m_resource_binding_by_argument.end() - ? resource_binding_by_argument_it->second : sp_empty_resource_binding; -} - -bool ProgramBase::ResourceBindingsBase::AllArgumentsAreBoundToResources(std::string& missing_args) const -{ - ITT_FUNCTION_TASK(); - - std::stringstream log_ss; - bool all_arguments_are_bound_to_resources = true; - for (const auto& resource_binding_by_argument : m_resource_binding_by_argument) - { - const Resource::Locations& resource_locations = resource_binding_by_argument.second->GetResourceLocations(); - if (resource_locations.empty()) - { - log_ss << std::endl - << " - Program \"" << m_sp_program->GetName() - << "\" argument \"" << resource_binding_by_argument.first.argument_name - << "\" of " << Shader::GetTypeName(resource_binding_by_argument.first.shader_type) - << " shader is not bound to any resource." ; - all_arguments_are_bound_to_resources = false; - } - } - - if (!all_arguments_are_bound_to_resources) - { - missing_args = log_ss.str(); - Platform::PrintToDebugOutput(missing_args); - } - return all_arguments_are_bound_to_resources; -} - -void ProgramBase::ResourceBindingsBase::VerifyAllArgumentsAreBoundToResources() -{ - ITT_FUNCTION_TASK(); - // Verify that resources are set for all program arguments -#ifndef PROGRAM_IGNORE_MISSING_ARGUMENTS - std::string missing_args; - if (!AllArgumentsAreBoundToResources(missing_args)) - { - throw std::runtime_error("Some arguments of program \"" + m_sp_program->GetName() + - "\" are not bound to any resource:\n" + missing_args); - } -#endif -} - -ProgramBase::ShadersByType ProgramBase::CreateShadersByType(const Shaders& shaders) +ProgramBase::ShadersByType ProgramBase::CreateShadersByType(const Ptrs& shaders) { ITT_FUNCTION_TASK(); ProgramBase::ShadersByType shaders_by_type; - for (const Shader::Ptr& sp_shader : shaders) + for (const Ptr& sp_shader : shaders) { if (!sp_shader) { @@ -295,12 +92,12 @@ ProgramBase::ShadersByType ProgramBase::CreateShadersByType(const Shaders& shade return shaders_by_type; } -Shader::Types CreateShaderTypes(const Shaders& shaders) +Shader::Types CreateShaderTypes(const Ptrs& shaders) { ITT_FUNCTION_TASK(); Shader::Types shader_types; - for (const Shader::Ptr& sp_shader : shaders) + for (const Ptr& sp_shader : shaders) { if (!sp_shader) { @@ -336,35 +133,35 @@ ProgramBase::~ProgramBase() } } -void ProgramBase::InitResourceBindings(const std::set& constant_argument_names, const std::set& addressable_argument_names) +void ProgramBase::InitArgumentBindings(const ArgumentDescriptions& argument_descriptions) { ITT_FUNCTION_TASK(); Shader::Types all_shader_types; std::map shader_types_by_argument_name_map; - m_resource_binding_by_argument.clear(); - for (const Shader::Ptr& sp_shader : m_settings.shaders) + m_binding_by_argument.clear(); + for (const Ptr& sp_shader : m_settings.shaders) { if (!sp_shader) { - throw std::runtime_error("Empty shader ponter in program is not allowed."); + throw std::runtime_error("Empty shader pointer in program is not allowed."); } const Shader::Type shader_type = sp_shader->GetType(); all_shader_types.insert(shader_type); - const Shader::ResourceBindings shader_resource_bindings = static_cast(*sp_shader).GetResourceBindings(constant_argument_names, addressable_argument_names); - for (const Shader::ResourceBinding::Ptr& sp_resource_binging : shader_resource_bindings) + const ShaderBase::ArgumentBindings argument_bindings = static_cast(*sp_shader).GetArgumentBindings(argument_descriptions); + for (const Ptr& sp_argument_binging : argument_bindings) { - if (!sp_resource_binging) + if (!sp_argument_binging) { throw std::runtime_error("Empty resource binding provided by shader."); } - const Argument shader_argument = { shader_type, sp_resource_binging->GetArgumentName() }; - m_resource_binding_by_argument.emplace(shader_argument, sp_resource_binging); - shader_types_by_argument_name_map[shader_argument.argument_name].insert(shader_argument.shader_type); + const Argument& shader_argument = sp_argument_binging->GetSettings().argument; + m_binding_by_argument.emplace(shader_argument, sp_argument_binging); + shader_types_by_argument_name_map[shader_argument.name].insert(shader_argument.shader_type); } } @@ -376,27 +173,27 @@ void ProgramBase::InitResourceBindings(const std::set& constant_arg continue; const std::string& argument_name = shader_types_by_argument_name.first; - Shader::ResourceBinding::Ptr sp_resource_binding; + Ptr sp_argument_binding; for(Shader::Type shader_type : all_shader_types) { const Argument argument = { shader_type, argument_name }; - auto resource_binding_by_argument_it = m_resource_binding_by_argument.find(argument); - if (resource_binding_by_argument_it == m_resource_binding_by_argument.end()) + auto binding_by_argument_it = m_binding_by_argument.find(argument); + if (binding_by_argument_it == m_binding_by_argument.end()) { throw std::runtime_error("Resource binding was not provided for " + Shader::GetTypeName(shader_type) + " shader argument \"" + argument_name + "\""); } - if (!sp_resource_binding) + if (!sp_argument_binding) { - sp_resource_binding = resource_binding_by_argument_it->second; + sp_argument_binding = binding_by_argument_it->second; } - m_resource_binding_by_argument.erase(resource_binding_by_argument_it); + m_binding_by_argument.erase(binding_by_argument_it); } - if (!sp_resource_binding) + if (!sp_argument_binding) { throw std::runtime_error("Failed to create resource binding for argument \"" + argument_name + "\"."); } - m_resource_binding_by_argument.emplace( Argument{ Shader::Type::All, argument_name }, sp_resource_binding); + m_binding_by_argument.emplace( Argument{ Shader::Type::All, argument_name }, sp_argument_binding); } } @@ -413,7 +210,7 @@ const DescriptorHeap::Range& ProgramBase::ReserveConstantDescriptorRange(Descrip const DescriptorHeapReservation& heap_reservation = constant_descriptor_range_by_heap_type_it->second; if (std::addressof(heap_reservation.heap.get()) != std::addressof(heap)) { - throw std::runtime_error("Constant descriptor range was previously reserver for the program on a different descriptor heap of the same type."); + throw std::runtime_error("Constant descriptor range was previously reserved for the program on a different descriptor heap of the same type."); } if (heap_reservation.range.GetLength() != range_length) { @@ -422,7 +219,7 @@ const DescriptorHeap::Range& ProgramBase::ReserveConstantDescriptorRange(Descrip return heap_reservation.range; } - DescriptorHeap::RangePtr sp_desc_range = heap.ReserveRange(range_length); + Ptr sp_desc_range = heap.ReserveRange(range_length); if (!sp_desc_range) { throw std::runtime_error("Descriptor heap does not have enough space to reserve constant descriptor range of a program."); @@ -434,7 +231,7 @@ Shader& ProgramBase::GetShaderRef(Shader::Type shader_type) { ITT_FUNCTION_TASK(); - const Shader::Ptr& sp_shader = GetShader(shader_type); + const Ptr& sp_shader = GetShader(shader_type); if (!sp_shader) { throw std::runtime_error(Shader::GetTypeName(shader_type) + "shader was not found in program \"" + GetName() + "\"."); @@ -442,25 +239,6 @@ Shader& ProgramBase::GetShaderRef(Shader::Type shader_type) return *sp_shader; } -uint32_t ProgramBase::GetInputBufferIndexByArgumentName(const std::string& argument_name) const -{ - ITT_FUNCTION_TASK(); - - for (size_t buffer_index = 0; buffer_index < m_settings.input_buffer_layouts.size(); buffer_index++) - { - const InputBufferLayout& input_buffer_layout = m_settings.input_buffer_layouts[buffer_index]; - auto argument_it = std::find_if(input_buffer_layout.arguments.begin(), input_buffer_layout.arguments.end(), - [&argument_name](const InputBufferLayout::Argument& argument) -> bool - { - return argument.name == argument_name; - }); - if (argument_it != input_buffer_layout.arguments.end()) - return static_cast(buffer_index); - } - - throw std::runtime_error("Input argument \"" + argument_name + "\" was not found for program \"" + GetName() + "\""); -} - uint32_t ProgramBase::GetInputBufferIndexByArgumentSemantic(const std::string& argument_semantic) const { ITT_FUNCTION_TASK(); @@ -468,12 +246,8 @@ uint32_t ProgramBase::GetInputBufferIndexByArgumentSemantic(const std::string& a for (size_t buffer_index = 0; buffer_index < m_settings.input_buffer_layouts.size(); buffer_index++) { const InputBufferLayout& input_buffer_layout = m_settings.input_buffer_layouts[buffer_index]; - auto argument_it = std::find_if(input_buffer_layout.arguments.begin(), input_buffer_layout.arguments.end(), - [&argument_semantic](const InputBufferLayout::Argument& argument) -> bool - { - return argument.semantic == argument_semantic; - }); - if (argument_it != input_buffer_layout.arguments.end()) + auto argument_it = std::find(input_buffer_layout.argument_semantics.begin(), input_buffer_layout.argument_semantics.end(), argument_semantic); + if (argument_it != input_buffer_layout.argument_semantics.end()) return static_cast(buffer_index); } diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/ProgramBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/ProgramBase.h index f2b76aa13..86a078607 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/ProgramBase.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/ProgramBase.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -45,82 +45,49 @@ class ProgramBase , public std::enable_shared_from_this { friend class ShaderBase; + friend class ProgramBindingsBase; public: - class ResourceBindingsBase - : public ResourceBindings - , public std::enable_shared_from_this - { - public: - using Ptr = std::shared_ptr; - - ResourceBindingsBase(const Program::Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument); - ResourceBindingsBase(const ResourceBindingsBase& other_resource_bingings, const ResourceLocationsByArgument& replace_resource_location_by_argument); - ~ResourceBindingsBase() override; - - Ptr GetPtr() { return shared_from_this(); } - const Arguments& GetArguments() const { return m_arguments; } - const Program& GetProgram() const { return *m_sp_program; } - - // ResourceBindings interface - const Shader::ResourceBinding::Ptr& Get(const Argument& shader_argument) const override; - - // ResourceBindingsBase interface - virtual void CompleteInitialization() = 0; - - bool AllArgumentsAreBoundToResources(std::string& missing_args) const; - - protected: - using DescriptorHeapReservationByType = std::array, static_cast(DescriptorHeap::Type::Count)>; - - void ReserveDescriptorHeapRanges(); - void SetResourcesForArguments(const ResourceLocationsByArgument& resource_locations_by_argument); - void VerifyAllArgumentsAreBoundToResources(); - - const Program::Ptr m_sp_program; - Arguments m_arguments; - ResourceBindingByArgument m_resource_binding_by_argument; - DescriptorHeapReservationByType m_descriptor_heap_reservations_by_type; - }; - ProgramBase(ContextBase& context, const Settings& settings); ~ProgramBase() override; // Program interface const Settings& GetSettings() const override { return m_settings; } const Shader::Types& GetShaderTypes() const override { return m_shader_types; } - const Shader::Ptr& GetShader(Shader::Type shader_type) const override { return m_shaders_by_type[static_cast(shader_type)]; } + const Ptr& GetShader(Shader::Type shader_type) const override { return m_shaders_by_type[static_cast(shader_type)]; } + bool HasShader(Shader::Type shader_type) const { return !!GetShader(shader_type); } - bool HasShader(Shader::Type shader_type) const { return !!GetShader(shader_type); } - ContextBase& GetContext() { return m_context; } - Ptr GetPtr() { return shared_from_this(); } + ContextBase& GetContext() { return m_context; } + const ContextBase& GetContext() const { return m_context; } + Ptr GetPtr() { return shared_from_this(); } protected: - void InitResourceBindings(const std::set& constant_argument_names, const std::set& addressable_argument_names); + void InitArgumentBindings(const ArgumentDescriptions& argument_descriptions); + const ProgramBindings::ArgumentBindings& GetArgumentBindings() const { return m_binding_by_argument; } const DescriptorHeap::Range& ReserveConstantDescriptorRange(DescriptorHeap& heap, uint32_t range_length); Shader& GetShaderRef(Shader::Type shader_type); - uint32_t GetInputBufferIndexByArgumentName(const std::string& argument_name) const; uint32_t GetInputBufferIndexByArgumentSemantic(const std::string& argument_semantic) const; - using ShadersByType = std::array(Shader::Type::Count)>; - static ShadersByType CreateShadersByType(const Shaders& shaders); + using ShadersByType = std::array, static_cast(Shader::Type::Count)>; + static ShadersByType CreateShadersByType(const Ptrs& shaders); +private: struct DescriptorHeapReservation { - DescriptorHeap::Ref heap; + Ref heap; DescriptorHeap::Range range; }; using DescriptorRangeByHeapType = std::map; - ContextBase& m_context; - const Settings m_settings; - const ShadersByType m_shaders_by_type; - const Shader::Types m_shader_types; - ResourceBindingByArgument m_resource_binding_by_argument; - DescriptorRangeByHeapType m_constant_descriptor_range_by_heap_type; - std::mutex m_constant_descriptor_ranges_reservation_mutex; + ContextBase& m_context; + const Settings m_settings; + const ShadersByType m_shaders_by_type; + const Shader::Types m_shader_types; + ProgramBindings::ArgumentBindings m_binding_by_argument; + DescriptorRangeByHeapType m_constant_descriptor_range_by_heap_type; + std::mutex m_constant_descriptor_ranges_reservation_mutex; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/ProgramBindingsBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/ProgramBindingsBase.cpp new file mode 100644 index 000000000..f4b2f8ff1 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/ProgramBindingsBase.cpp @@ -0,0 +1,359 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/ProgramBindingsBase.cpp +Base implementation of the program bindings interface. + +******************************************************************************/ + +#include "ProgramBindingsBase.h" +#include "ContextBase.h" + +#include +#include + +#include + +namespace Methane::Graphics +{ + +ProgramBindingsBase::ArgumentBindingBase::ArgumentBindingBase(const ContextBase& context, Settings settings) + : m_context(context) + , m_settings(std::move(settings)) +{ + ITT_FUNCTION_TASK(); +} + +void ProgramBindingsBase::ArgumentBindingBase::SetResourceLocations(const Resource::Locations& resource_locations) +{ + ITT_FUNCTION_TASK(); + + m_resource_locations.clear(); + if (resource_locations.empty()) + throw std::invalid_argument("Can not set empty resources for resource binding."); + + const bool is_addressable_binding = m_settings.argument.IsAddressable(); + const Resource::Type bound_resource_type = m_settings.resource_type; + + for (const Resource::Location& resource_location : resource_locations) + { + if (resource_location.GetResource().GetResourceType() != bound_resource_type) + { + throw std::invalid_argument("Incompatible resource type \"" + Resource::GetTypeName(resource_location.GetResource().GetResourceType()) + + "\" is bound to argument \"" + m_settings.argument.name + + "\" of type \"" + Resource::GetTypeName(bound_resource_type) + "\"."); + } + + const Resource::Usage::Mask resource_usage_mask = resource_location.GetResource().GetUsageMask(); + if (static_cast(resource_usage_mask & Resource::Usage::Addressable) != is_addressable_binding) + throw std::invalid_argument("Resource addressable usage flag does not match with resource binding state."); + + if (!is_addressable_binding && resource_location.GetOffset() > 0) + throw std::invalid_argument("Can not set resource location with non-zero offset to non-addressable resource binding."); + } + + m_resource_locations = resource_locations; +} + +DescriptorHeap::Type ProgramBindingsBase::ArgumentBindingBase::GetDescriptorHeapType() const +{ + ITT_FUNCTION_TASK(); + return (m_settings.resource_type == Resource::Type::Sampler) + ? DescriptorHeap::Type::Samplers + : DescriptorHeap::Type::ShaderResources; +} + +bool ProgramBindingsBase::ArgumentBindingBase::IsAlreadyApplied(const Program& program, + const ProgramBindingsBase& applied_program_bindings, + bool check_binding_value_changes) const +{ + ITT_FUNCTION_TASK(); + + if (std::addressof(applied_program_bindings.GetProgram()) != std::addressof(program)) + return false; + + // 1) No need in setting constant resource binding + // when another binding was previously set in the same command list for the same program + if (m_settings.argument.IsConstant()) + return true; + + if (!check_binding_value_changes) + return false; + + const Ptr& previous_argument_argument_binding = applied_program_bindings.Get(m_settings.argument); + if (!previous_argument_argument_binding) + return false; + + // 2) No need in setting resource binding to the same location + // as a previous resource binding set in the same command list for the same program + if (previous_argument_argument_binding->GetResourceLocations() == m_resource_locations) + return true; + + return false; +} + +ProgramBindingsBase::ProgramBindingsBase(const Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument) + : m_sp_program(sp_program) +{ + ITT_FUNCTION_TASK(); + + if (!m_sp_program) + { + throw std::runtime_error("Can not create resource bindings for an empty program."); + } + + ReserveDescriptorHeapRanges(); + SetResourcesForArguments(resource_locations_by_argument); + VerifyAllArgumentsAreBoundToResources(); +} + +ProgramBindingsBase::ProgramBindingsBase(const ProgramBindingsBase& other_program_bindings, const ResourceLocationsByArgument& replace_resource_locations_by_argument) + : m_sp_program(other_program_bindings.m_sp_program) + , m_descriptor_heap_reservations_by_type(other_program_bindings.m_descriptor_heap_reservations_by_type) +{ + ITT_FUNCTION_TASK(); + + // Form map of volatile resource bindings with replaced resource locations + ResourceLocationsByArgument resource_locations_by_argument = replace_resource_locations_by_argument; + for (const auto& argument_and_argument_binding : other_program_bindings.m_binding_by_argument) + { + // NOTE: constant resource bindings are reusing single binding-object for the whole program, + // so there's no need in setting its value, since it was already set by the original resource binding + if (argument_and_argument_binding.second->GetSettings().argument.IsConstant() || + resource_locations_by_argument.count(argument_and_argument_binding.first)) + continue; + + resource_locations_by_argument.emplace( + argument_and_argument_binding.first, + argument_and_argument_binding.second->GetResourceLocations() + ); + } + + ReserveDescriptorHeapRanges(); + SetResourcesForArguments(resource_locations_by_argument); + VerifyAllArgumentsAreBoundToResources(); +} + +ProgramBindingsBase::~ProgramBindingsBase() +{ + ITT_FUNCTION_TASK(); + + // Release mutable descriptor ranges in heaps (constant ranges are released by the program) + for (const auto& descriptor_type_and_heap_reservation : m_descriptor_heap_reservations_by_type) + { + if (!descriptor_type_and_heap_reservation) + continue; + + const DescriptorHeap::Reservation& heap_reservation = *descriptor_type_and_heap_reservation; + if (heap_reservation.mutable_range.IsEmpty()) + continue; + + heap_reservation.heap.get().ReleaseRange(heap_reservation.mutable_range); + } +} + +const Program& ProgramBindingsBase::GetProgram() const +{ + ITT_FUNCTION_TASK(); + assert(!!m_sp_program); + return *m_sp_program; +} + +Program& ProgramBindingsBase::GetProgram() +{ + ITT_FUNCTION_TASK(); + assert(!!m_sp_program); + return *m_sp_program; +} + +void ProgramBindingsBase::ReserveDescriptorHeapRanges() +{ + ITT_FUNCTION_TASK(); + + struct DescriptorsCount + { + uint32_t constant_count = 0; + uint32_t mutable_count = 0; + }; + + assert(!!m_sp_program); + const ProgramBase& program = static_cast(GetProgram()); + + // Count the number of constant and mutable descriptors to be allocated in each descriptor heap + std::map descriptors_count_by_heap_type; + for (const auto& binding_by_argument : program.GetArgumentBindings()) + { + if (!binding_by_argument.second) + { + throw std::runtime_error("No resource binding is set for an argument \"" + binding_by_argument.first.name + "\" of shader."); + } + + const ArgumentBindingBase& argument_binding = static_cast(*binding_by_argument.second); + const ArgumentBinding::Settings& binding_settings = argument_binding.GetSettings(); + m_arguments.insert(binding_by_argument.first); + + auto binding_by_argument_it = m_binding_by_argument.find(binding_by_argument.first); + if (binding_by_argument_it == m_binding_by_argument.end()) + { + m_binding_by_argument.emplace( + binding_by_argument.first, + binding_settings.argument.IsConstant() + ? binding_by_argument.second + : ArgumentBindingBase::CreateCopy(argument_binding) + ); + } + else if (!binding_settings.argument.IsConstant()) + { + binding_by_argument_it->second = ArgumentBindingBase::CreateCopy(static_cast(*binding_by_argument_it->second)); + } + + // NOTE: addressable resource bindings do not require descriptors to be created, instead they use direct GPU memory offset from resource + if (binding_settings.argument.IsAddressable()) + continue; + + const DescriptorHeap::Type heap_type = argument_binding.GetDescriptorHeapType(); + DescriptorsCount& descriptors = descriptors_count_by_heap_type[heap_type]; + if (binding_settings.argument.IsConstant()) + { + descriptors.constant_count += binding_settings.resource_count; + } + else + { + descriptors.mutable_count += binding_settings.resource_count; + } + } + + // Reserve descriptor ranges in heaps for resource bindings state + const ResourceManager& resource_manager = program.GetContext().GetResourceManager(); + for (const auto& descriptor_heap_type_and_count : descriptors_count_by_heap_type) + { + const DescriptorHeap::Type heap_type = descriptor_heap_type_and_count.first; + const DescriptorsCount& descriptors = descriptor_heap_type_and_count.second; + + std::optional& descriptor_heap_reservation_opt = m_descriptor_heap_reservations_by_type[static_cast(heap_type)]; + if (!descriptor_heap_reservation_opt) + { + descriptor_heap_reservation_opt.emplace( + resource_manager.GetDefaultShaderVisibleDescriptorHeap(heap_type), + DescriptorHeap::Range(0, 0), + DescriptorHeap::Range(0, 0) + ); + } + + DescriptorHeap::Reservation& heap_reservation = *descriptor_heap_reservation_opt; + if (descriptors.constant_count > 0) + { + heap_reservation.constant_range = static_cast(*m_sp_program).ReserveConstantDescriptorRange(heap_reservation.heap.get(), descriptors.constant_count); + } + if (descriptors.mutable_count > 0) + { + Ptr sp_mutable_heap_range = heap_reservation.heap.get().ReserveRange(descriptors.mutable_count); + if (!sp_mutable_heap_range) + { + throw std::runtime_error("Failed to reserve mutable descriptor heap range. Descriptor heap is not big enough."); + } + heap_reservation.mutable_range = *sp_mutable_heap_range; + } + } +} + +void ProgramBindingsBase::SetResourcesForArguments(const ResourceLocationsByArgument& resource_locations_by_argument) +{ + ITT_FUNCTION_TASK(); + + for (const auto& argument_and_resource_locations : resource_locations_by_argument) + { + const Program::Argument argument = argument_and_resource_locations.first; + const Ptr& sp_binding = Get(argument); + if (!sp_binding) + { +#ifndef PROGRAM_IGNORE_MISSING_ARGUMENTS + const Program::Argument all_shaders_argument(Shader::Type::All, argument.name); + const bool all_shaders_argument_found = !!Get(all_shaders_argument); + throw std::runtime_error("Program \"" + m_sp_program->GetName() + + "\" does not have argument \"" + argument.name + + "\" of " + Shader::GetTypeName(argument.shader_type) + " shader." + + (all_shaders_argument_found ? " Instead this argument is used in All shaders." : "") ); +#else + continue; +#endif + } + sp_binding->SetResourceLocations(argument_and_resource_locations.second); + } +} + +const Ptr& ProgramBindingsBase::Get(const Program::Argument& shader_argument) const +{ + ITT_FUNCTION_TASK(); + + static const Ptr s_sp_empty_argument_binding; + auto binding_by_argument_it = m_binding_by_argument.find(shader_argument); + return binding_by_argument_it != m_binding_by_argument.end() + ? binding_by_argument_it->second : s_sp_empty_argument_binding; +} + +bool ProgramBindingsBase::AllArgumentsAreBoundToResources(std::string& missing_args) const +{ + ITT_FUNCTION_TASK(); + + std::stringstream log_ss; + bool all_arguments_are_bound_to_resources = true; + for (const auto& binding_by_argument : m_binding_by_argument) + { + const Resource::Locations& resource_locations = binding_by_argument.second->GetResourceLocations(); + if (resource_locations.empty()) + { + log_ss << std::endl + << " - Program \"" << m_sp_program->GetName() + << "\" argument \"" << binding_by_argument.first.name + << "\" of " << Shader::GetTypeName(binding_by_argument.first.shader_type) + << " shader is not bound to any resource." ; + all_arguments_are_bound_to_resources = false; + } + } + + if (!all_arguments_are_bound_to_resources) + { + missing_args = log_ss.str(); + Platform::PrintToDebugOutput(missing_args); + } + return all_arguments_are_bound_to_resources; +} + +void ProgramBindingsBase::VerifyAllArgumentsAreBoundToResources() +{ + ITT_FUNCTION_TASK(); + // Verify that resources are set for all program arguments +#ifndef PROGRAM_IGNORE_MISSING_ARGUMENTS + std::string missing_args; + if (!AllArgumentsAreBoundToResources(missing_args)) + { + throw std::runtime_error("Some arguments of program \"" + m_sp_program->GetName() + + "\" are not bound to any resource:\n" + missing_args); + } +#endif +} + +const std::optional& ProgramBindingsBase::GetDescriptorHeapReservationByType(DescriptorHeap::Type heap_type) const +{ + ITT_FUNCTION_TASK(); + assert(heap_type != DescriptorHeap::Type::Undefined); + return m_descriptor_heap_reservations_by_type[static_cast(heap_type)]; +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/ProgramBindingsBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/ProgramBindingsBase.h new file mode 100644 index 000000000..b35cd562b --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/ProgramBindingsBase.h @@ -0,0 +1,113 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/ProgramBindingsBase.h +Base implementation of the program bindings interface. + +******************************************************************************/ + +#pragma once + +#include +#include + +#include "DescriptorHeap.h" +#include "CommandListBase.h" + +#include + +namespace Methane::Graphics +{ + +class ContextBase; +class CommandListBase; + +class ProgramBindingsBase + : public ProgramBindings + , public std::enable_shared_from_this +{ +public: + class ArgumentBindingBase + : public ArgumentBinding + , public std::enable_shared_from_this + { + public: + static Ptr CreateCopy(const ArgumentBindingBase& other_argument_binding); + + ArgumentBindingBase(const ContextBase& context, Settings settings); + ArgumentBindingBase(const ArgumentBindingBase& other) = default; + + // ArgumentBinding interface + const Settings& GetSettings() const noexcept override { return m_settings; } + const Resource::Locations& GetResourceLocations() const noexcept override { return m_resource_locations; } + void SetResourceLocations(const Resource::Locations& resource_locations) override; + + DescriptorHeap::Type GetDescriptorHeapType() const; + Ptr GetPtr() { return shared_from_this(); } + + bool IsAlreadyApplied(const Program& program, + const ProgramBindingsBase& applied_program_bindings, + bool check_binding_value_changes = true) const; + protected: + const ContextBase& GetContext() const noexcept { return m_context; } + + private: + const ContextBase& m_context; + const Settings m_settings; + Resource::Locations m_resource_locations; + }; + + ProgramBindingsBase(const Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument); + ProgramBindingsBase(const ProgramBindingsBase& other_program_bindings, const ResourceLocationsByArgument& replace_resource_location_by_argument); + ~ProgramBindingsBase() override; + + Ptr GetPtr() { return shared_from_this(); } + const Program::Arguments& GetArguments() const { return m_arguments; } + const Program& GetProgram() const; + + // ProgramBindings interface + const Ptr& Get(const Program::Argument& shader_argument) const override; + + // ProgramBindingsBase interface + virtual void CompleteInitialization() = 0; + virtual void Apply(CommandListBase& command_list, ApplyBehavior::Mask apply_behavior = ApplyBehavior::AllIncremental) const = 0; + + bool AllArgumentsAreBoundToResources(std::string& missing_args) const; + +protected: + Program& GetProgram(); + void ReserveDescriptorHeapRanges(); + void SetResourcesForArguments(const ResourceLocationsByArgument& resource_locations_by_argument); + void VerifyAllArgumentsAreBoundToResources(); + + using BindingByArgument = std::unordered_map, Program::Argument::Hash>; + const BindingByArgument& GetArgumentBindings() const { return m_binding_by_argument; } + + const std::optional& GetDescriptorHeapReservationByType(DescriptorHeap::Type heap_type) const; + +private: + using DescriptorHeapReservationByType = std::array, + static_cast(DescriptorHeap::Type::Count)>; + + const Ptr m_sp_program; + Program::Arguments m_arguments; + BindingByArgument m_binding_by_argument; + DescriptorHeapReservationByType m_descriptor_heap_reservations_by_type; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/RenderCommandListBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/RenderCommandListBase.cpp index 83681aee9..25f0ef7d8 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/RenderCommandListBase.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/RenderCommandListBase.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ Base implementation of the render command list interface. #include "BufferBase.h" #include "ProgramBase.h" -#include +#include #include @@ -37,7 +37,7 @@ namespace Methane::Graphics { RenderCommandListBase::RenderCommandListBase(CommandQueueBase& command_queue, RenderPassBase& pass) - : CommandListBase(command_queue, Type::RenderCommandList) + : CommandListBase(command_queue, Type::Render) , m_is_parallel(false) , m_sp_pass(pass.GetPtr()) { @@ -45,45 +45,21 @@ RenderCommandListBase::RenderCommandListBase(CommandQueueBase& command_queue, Re } RenderCommandListBase::RenderCommandListBase(ParallelRenderCommandListBase& parallel_render_command_list) - : CommandListBase(static_cast(parallel_render_command_list.GetCommandQueue()), Type::RenderCommandList) + : CommandListBase(static_cast(parallel_render_command_list.GetCommandQueue()), Type::Render) , m_is_parallel(true) - , m_sp_pass(static_cast(parallel_render_command_list.GetPass()).GetPtr()) + , m_sp_pass(parallel_render_command_list.GetPass().GetPtr()) , m_wp_parallel_render_command_list(std::static_pointer_cast(parallel_render_command_list.GetPtr())) { ITT_FUNCTION_TASK(); } -void RenderCommandListBase::DrawingState::Reset() +void RenderCommandListBase::Reset(const Ptr& sp_render_state, const std::string& debug_group) { ITT_FUNCTION_TASK(); - opt_primitive_type.reset(); - sp_index_buffer.reset(); - sp_vertex_buffers.clear(); - sp_render_state.reset(); + CommandListBase::Reset(debug_group); - flags = { }; -} - -void RenderCommandListBase::Reset(const RenderState::Ptr& sp_render_state, const std::string& debug_group) -{ - ITT_FUNCTION_TASK(); - - // ResetDrawState() must be called from an overriden Reset method - - ResetCommandState(); - - if (m_debug_group_opened) - { - PopDebugGroup(); - m_debug_group_opened = false; - } - - if (!debug_group.empty()) - { - PushDebugGroup(debug_group); - m_debug_group_opened = true; - } + // ResetCommandState() must be called from the top-most overridden Reset method if (sp_render_state) { @@ -95,21 +71,22 @@ void RenderCommandListBase::SetState(RenderState& render_state, RenderState::Gro { ITT_FUNCTION_TASK(); - const RenderState::Group::Mask changed_states = (m_draw_state.sp_render_state + DrawingState& drawing_state = GetDrawingState(); + const RenderState::Group::Mask changed_states = (drawing_state.p_render_state ? RenderState::Settings::Compare(render_state.GetSettings(), - m_draw_state.sp_render_state->GetSettings(), - m_draw_state.render_state_groups) + drawing_state.p_render_state->GetSettings(), + drawing_state.render_state_groups) : RenderState::Group::All) - | ~m_draw_state.render_state_groups; + | ~drawing_state.render_state_groups; RenderStateBase& render_state_base = static_cast(render_state); render_state_base.Apply(*this, changed_states & state_groups); - m_draw_state.sp_render_state = render_state_base.GetPtr(); - m_draw_state.render_state_groups |= state_groups; + drawing_state.p_render_state = &render_state_base; + drawing_state.render_state_groups |= state_groups; } -void RenderCommandListBase::SetVertexBuffers(const Buffer::Refs& vertex_buffers) +void RenderCommandListBase::SetVertexBuffers(const Refs& vertex_buffers) { ITT_FUNCTION_TASK(); if (vertex_buffers.empty()) @@ -117,11 +94,12 @@ void RenderCommandListBase::SetVertexBuffers(const Buffer::Refs& vertex_buffers) throw std::invalid_argument("Can not set empty vertex buffers."); } - m_draw_state.flags.vertex_buffers_changed = m_draw_state.sp_vertex_buffers.size() != vertex_buffers.size(); - m_draw_state.sp_vertex_buffers.resize(vertex_buffers.size()); + DrawingState& drawing_state = GetDrawingState(); + drawing_state.flags.vertex_buffers_changed = drawing_state.vertex_buffers.size() != vertex_buffers.size(); + drawing_state.vertex_buffers.resize(vertex_buffers.size()); uint32_t vertex_buffer_index = 0; - for (const Buffer::Ref& vertex_buffer_ref : vertex_buffers) + for (const Ref& vertex_buffer_ref : vertex_buffers) { BufferBase& vertex_buffer = static_cast(vertex_buffer_ref.get()); @@ -136,15 +114,15 @@ void RenderCommandListBase::SetVertexBuffers(const Buffer::Refs& vertex_buffers) throw std::invalid_argument("Can not set empty vertex buffer."); } - if (!m_draw_state.flags.vertex_buffers_changed && - (vertex_buffer_index >= m_draw_state.sp_vertex_buffers.size() || - !m_draw_state.sp_vertex_buffers[vertex_buffer_index] || - m_draw_state.sp_vertex_buffers[vertex_buffer_index].get() != std::addressof(vertex_buffer))) + if (!drawing_state.flags.vertex_buffers_changed && + (vertex_buffer_index >= drawing_state.vertex_buffers.size() || + !drawing_state.vertex_buffers[vertex_buffer_index] || + drawing_state.vertex_buffers[vertex_buffer_index] != std::addressof(vertex_buffer))) { - m_draw_state.flags.vertex_buffers_changed = true; + drawing_state.flags.vertex_buffers_changed = true; } - m_draw_state.sp_vertex_buffers[vertex_buffer_index] = vertex_buffer.GetPtr(); + drawing_state.vertex_buffers[vertex_buffer_index] = &vertex_buffer; vertex_buffer_index++; } } @@ -182,11 +160,12 @@ void RenderCommandListBase::DrawIndexed(Primitive primitive_type, Buffer& index_ ValidateDrawVertexBuffers(start_vertex); - m_draw_state.flags.index_buffer_changed = !m_draw_state.sp_index_buffer || m_draw_state.sp_index_buffer.get() != std::addressof(index_buffer); - m_draw_state.sp_index_buffer = static_cast(index_buffer).GetPtr(); + DrawingState& drawing_state = GetDrawingState(); + drawing_state.flags.index_buffer_changed = !drawing_state.p_index_buffer || drawing_state.p_index_buffer != std::addressof(index_buffer); + drawing_state.p_index_buffer = static_cast(&index_buffer); - m_draw_state.flags.primitive_type_changed = !m_draw_state.opt_primitive_type || *m_draw_state.opt_primitive_type != primitive_type; - m_draw_state.opt_primitive_type = primitive_type; + drawing_state.flags.primitive_type_changed = !drawing_state.opt_primitive_type || *drawing_state.opt_primitive_type != primitive_type; + drawing_state.opt_primitive_type = primitive_type; } void RenderCommandListBase::Draw(Primitive primitive_type, uint32_t vertex_count, uint32_t start_vertex, @@ -205,21 +184,18 @@ void RenderCommandListBase::Draw(Primitive primitive_type, uint32_t vertex_count ValidateDrawVertexBuffers(start_vertex, vertex_count); - m_draw_state.flags.primitive_type_changed = !m_draw_state.opt_primitive_type || *m_draw_state.opt_primitive_type != primitive_type; - m_draw_state.opt_primitive_type = primitive_type; -} - -void RenderCommandListBase::ResetDrawState() -{ - m_draw_state.Reset(); + DrawingState& drawing_state = GetDrawingState(); + drawing_state.flags.primitive_type_changed = !drawing_state.opt_primitive_type || *drawing_state.opt_primitive_type != primitive_type; + drawing_state.opt_primitive_type = primitive_type; } void RenderCommandListBase::ValidateDrawVertexBuffers(uint32_t draw_start_vertex, uint32_t draw_vertex_count) { - for (const BufferBase::Ptr& sp_vertex_buffer : m_draw_state.sp_vertex_buffers) + DrawingState& drawing_state = GetDrawingState(); + for (BufferBase* p_vertex_buffer : drawing_state.vertex_buffers) { - assert(!!sp_vertex_buffer); - const BufferBase& vertex_buffer = *sp_vertex_buffer; + assert(!!p_vertex_buffer); + const BufferBase& vertex_buffer = *p_vertex_buffer; const uint32_t vertex_count = vertex_buffer.GetFormattedItemsCount(); if (draw_start_vertex + draw_vertex_count <= vertex_count) return; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/RenderCommandListBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/RenderCommandListBase.h index e4221c64f..43f3e5bf1 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/RenderCommandListBase.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/RenderCommandListBase.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -43,15 +43,37 @@ class RenderCommandListBase , public CommandListBase { public: - using Ptr = std::shared_ptr; + struct DrawingState final : CommandState + { + struct Flags + { + bool primitive_type_changed = false; + bool index_buffer_changed = false; + bool vertex_buffers_changed = false; + }; + + // NOTE: justification why raw pointers are used is provided in base class notice, see CommandState for more details + + std::optional opt_primitive_type; + BufferBase* p_index_buffer = nullptr; + std::vector vertex_buffers; + RenderStateBase* p_render_state = nullptr; + RenderState::Group::Mask render_state_groups; + + Flags flags; + + DrawingState() = default; + }; RenderCommandListBase(CommandQueueBase& command_queue, RenderPassBase& render_pass); RenderCommandListBase(ParallelRenderCommandListBase& parallel_render_command_list); + + using CommandListBase::Reset; // RenderCommandList interface - void Reset(const RenderState::Ptr& sp_render_state, const std::string& debug_group = "") override; + void Reset(const Ptr& sp_render_state, const std::string& debug_group = "") override; void SetState(RenderState& render_state, RenderState::Group::Mask state_groups = RenderState::Group::All) override; - void SetVertexBuffers(const Buffer::Refs& vertex_buffers) override; + void SetVertexBuffers(const Refs& vertex_buffers) override; void DrawIndexed(Primitive primitive_type, Buffer& index_buffer, uint32_t index_count, uint32_t start_index, uint32_t start_vertex, uint32_t instance_count, uint32_t start_instance) override; @@ -61,34 +83,16 @@ class RenderCommandListBase RenderPassBase& GetPass(); protected: - void ResetDrawState(); void ValidateDrawVertexBuffers(uint32_t draw_start_vertex, uint32_t draw_vertex_count = 0); - - struct DrawingState - { - struct Flags - { - bool primitive_type_changed = false; - bool index_buffer_changed = false; - bool vertex_buffers_changed = false; - }; - - std::optional opt_primitive_type; - BufferBase::Ptr sp_index_buffer; - BufferBase::Ptrs sp_vertex_buffers; - RenderStateBase::Ptr sp_render_state; - RenderState::Group::Mask render_state_groups; - - Flags flags; - - void Reset(); - }; - - const bool m_is_parallel; - const RenderPass::Ptr m_sp_pass; - DrawingState m_draw_state; - - std::weak_ptr m_wp_parallel_render_command_list; + DrawingState& GetDrawingState() { return static_cast(GetCommandState()); } + const DrawingState& GetDrawingState() const { return static_cast(GetCommandState()); } + bool IsParallel() const { return m_is_parallel; } + Ptr GetParallelRenderCommandList() { return m_wp_parallel_render_command_list.lock(); } + +private: + const bool m_is_parallel; + const Ptr m_sp_pass; + WeakPtr m_wp_parallel_render_command_list; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/RenderContextBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/RenderContextBase.cpp new file mode 100644 index 000000000..86ddf099a --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/RenderContextBase.cpp @@ -0,0 +1,266 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/RenderContextBase.cpp +Base implementation of the render context interface. + +******************************************************************************/ + +#include "RenderContextBase.h" +#include "DeviceBase.h" + +#include + +#ifdef COMMAND_EXECUTION_LOGGING +#include +#endif + +#include + +namespace Methane::Graphics +{ + +RenderContextBase::RenderContextBase(DeviceBase& device, const Settings& settings) + : ContextBase(device, Type::Render) + , m_settings(settings) + , m_frame_buffer_index(0) +{ + ITT_FUNCTION_TASK(); +} + +void RenderContextBase::WaitForGpu(WaitFor wait_for) +{ + ITT_FUNCTION_TASK(); + + ContextBase::WaitForGpu(wait_for); + + switch (wait_for) + { + case WaitFor::RenderComplete: + { + SCOPE_TIMER("RenderContextDX::WaitForGpu::RenderComplete"); + OnGpuWaitStart(wait_for); + GetRenderFence().Flush(); + OnGpuWaitComplete(wait_for); + } break; + + case WaitFor::FramePresented: + { + SCOPE_TIMER("RenderContextDX::WaitForGpu::FramePresented"); + OnGpuWaitStart(wait_for); + GetCurrentFrameFence().Wait(); + OnGpuWaitComplete(wait_for); + } break; + + case WaitFor::ResourcesUploaded: break; // Handled in ContextBase::WaitForGpu + } +} + +void RenderContextBase::Resize(const FrameSize& frame_size) +{ + ITT_FUNCTION_TASK(); + +#ifdef COMMAND_EXECUTION_LOGGING + Platform::PrintToDebugOutput("RESIZE context \"" + GetName() + "\" from " + static_cast(m_settings.frame_size) + " to " + static_cast(frame_size)); +#endif + + m_settings.frame_size = frame_size; +} + +void RenderContextBase::Present() +{ + ITT_FUNCTION_TASK(); + +#ifdef COMMAND_EXECUTION_LOGGING + Platform::PrintToDebugOutput("PRESENT frame " + std::to_string(m_frame_buffer_index) + " in context \"" + GetName() + "\""); +#endif + + m_fps_counter.OnCpuFrameReadyToPresent(); +} + +void RenderContextBase::OnCpuPresentComplete(bool signal_frame_fence) +{ + ITT_FUNCTION_TASK(); + + if (signal_frame_fence) + { + // Schedule a signal command in the queue for a currently finished frame + GetCurrentFrameFence().Signal(); + } + +#ifdef COMMAND_EXECUTION_LOGGING + Platform::PrintToDebugOutput("PRESENT COMPLETE for context \"" + GetName() + "\""); +#endif + + m_fps_counter.OnCpuFramePresented(); +} + +Fence& RenderContextBase::GetCurrentFrameFence() const +{ + ITT_FUNCTION_TASK(); + const UniquePtr& sp_current_fence = GetCurrentFrameFencePtr(); + assert(!!sp_current_fence); + return *sp_current_fence; +} + +Fence& RenderContextBase::GetRenderFence() const +{ + ITT_FUNCTION_TASK(); + assert(!!m_sp_render_fence); + return *m_sp_render_fence; +} + +void RenderContextBase::ResetWithSettings(const Settings& settings) +{ + ITT_FUNCTION_TASK(); + +#ifdef COMMAND_EXECUTION_LOGGING + Platform::PrintToDebugOutput("RESET context \"" + GetName() + "\" with new settings."); +#endif + + WaitForGpu(WaitFor::RenderComplete); + + Ptr sp_device = GetDeviceBase().GetPtr(); + m_settings = settings; + + Release(); + Initialize(*sp_device, true); +} + +void RenderContextBase::Initialize(DeviceBase& device, bool deferred_heap_allocation) +{ + ITT_FUNCTION_TASK(); + + ContextBase::Initialize(device, deferred_heap_allocation); + + m_frame_fences.clear(); + for (uint32_t frame_index = 0; frame_index < m_settings.frame_buffers_count; ++frame_index) + { + m_frame_fences.emplace_back(Fence::Create(GetRenderCommandQueue())); + } + + m_sp_render_fence = Fence::Create(GetRenderCommandQueue()); +} + +void RenderContextBase::Release() +{ + ITT_FUNCTION_TASK(); + + m_sp_render_fence.reset(); + m_frame_fences.clear(); + m_sp_render_cmd_queue.reset(); + + ContextBase::Release(); +} + +void RenderContextBase::SetName(const std::string& name) +{ + ITT_FUNCTION_TASK(); + + ContextBase::SetName(name); + + for (uint32_t frame_index = 0; frame_index < m_frame_fences.size(); ++frame_index) + { + const UniquePtr& sp_frame_fence = m_frame_fences[frame_index]; + assert(!!sp_frame_fence); + sp_frame_fence->SetName(name + " Frame " + std::to_string(frame_index) + " Fence"); + } + + if (m_sp_render_fence) + m_sp_render_fence->SetName(name + " Render Fence"); +} + +void RenderContextBase::OnGpuWaitStart(WaitFor wait_for) +{ + ITT_FUNCTION_TASK(); + if (wait_for == WaitFor::FramePresented) + { + m_fps_counter.OnGpuFramePresentWait(); + } + ContextBase::OnGpuWaitStart(wait_for); +} + +void RenderContextBase::OnGpuWaitComplete(WaitFor wait_for) +{ + ITT_FUNCTION_TASK(); + if (wait_for == WaitFor::FramePresented) + { + m_fps_counter.OnGpuFramePresented(); + } + ContextBase::OnGpuWaitComplete(wait_for); +} + +void RenderContextBase::UpdateFrameBufferIndex() +{ + m_frame_buffer_index = GetNextFrameBufferIndex(); +} + +uint32_t RenderContextBase::GetNextFrameBufferIndex() +{ + return (m_frame_buffer_index + 1) % m_settings.frame_buffers_count; +} + +CommandQueue& RenderContextBase::GetRenderCommandQueue() +{ + ITT_FUNCTION_TASK(); + if (!m_sp_render_cmd_queue) + { + m_sp_render_cmd_queue = CommandQueue::Create(*this); + m_sp_render_cmd_queue->SetName("Render Command Queue"); + } + return *m_sp_render_cmd_queue; +} + +bool RenderContextBase::SetVSyncEnabled(bool vsync_enabled) +{ + ITT_FUNCTION_TASK(); + if (m_settings.vsync_enabled == vsync_enabled) + return false; + + m_settings.vsync_enabled = vsync_enabled; + return true; +} + +bool RenderContextBase::SetFrameBuffersCount(uint32_t frame_buffers_count) +{ + ITT_FUNCTION_TASK(); + frame_buffers_count = std::min(std::max(2u, frame_buffers_count), 10u); + + if (m_settings.frame_buffers_count == frame_buffers_count) + return false; + + Settings new_settings = m_settings; + new_settings.frame_buffers_count = frame_buffers_count; + ResetWithSettings(new_settings); + + return true; +} + +bool RenderContextBase::SetFullScreen(bool is_full_screen) +{ + ITT_FUNCTION_TASK(); + if (m_settings.is_full_screen == is_full_screen) + return false; + + // No need to reset context for switching to full-screen + // Application window state is kept in sync with context by the user code and handles window resizing + m_settings.is_full_screen = is_full_screen; + return true; +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/RenderContextBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/RenderContextBase.h new file mode 100644 index 000000000..5d915d530 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/RenderContextBase.h @@ -0,0 +1,88 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/RenderContextBase.h +Base implementation of the render context interface. + +******************************************************************************/ + +#pragma once + +#include "ContextBase.h" +#include "FenceBase.h" + +#include +#include + +namespace Methane::Graphics +{ + +class RenderContextBase + : public ContextBase + , public RenderContext +{ +public: + RenderContextBase(DeviceBase& device, const Settings& settings); + + // Context interface + void WaitForGpu(WaitFor wait_for) override; + + // RenderContext interface + void Resize(const FrameSize& frame_size) override; + void Present() override; + CommandQueue& GetRenderCommandQueue() override; + const Settings& GetSettings() const override { return m_settings; } + uint32_t GetFrameBufferIndex() const override { return m_frame_buffer_index; } + const FpsCounter& GetFpsCounter() const override { return m_fps_counter; } + bool SetVSyncEnabled(bool vsync_enabled) override; + bool SetFrameBuffersCount(uint32_t frame_buffers_count) override; + bool SetFullScreen(bool is_full_screen) override; + + // ContextBase interface + void Initialize(DeviceBase& device, bool deferred_heap_allocation) override; + void Release() override; + + // Object interface + void SetName(const std::string& name) override; + +protected: + void ResetWithSettings(const Settings& settings); + void OnCpuPresentComplete(bool signal_frame_fence = true); + void UpdateFrameBufferIndex(); + + inline const UniquePtr& GetCurrentFrameFencePtr() const { return m_frame_fences[m_frame_buffer_index]; } + Fence& GetCurrentFrameFence() const; + Fence& GetRenderFence() const; + + // ContextBase overrides + void OnGpuWaitStart(WaitFor wait_for) override; + void OnGpuWaitComplete(WaitFor wait_for) override; + + // RenderContextBase + virtual uint32_t GetNextFrameBufferIndex(); + +private: + Settings m_settings; + Ptr m_sp_render_cmd_queue; + UniquePtrs m_frame_fences; + UniquePtr m_sp_render_fence; + uint32_t m_frame_buffer_index; + FpsCounter m_fps_counter; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/RenderPassBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/RenderPassBase.cpp index 105599d89..f1a2b39c6 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/RenderPassBase.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/RenderPassBase.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ Base implementation of the render pass interface. #include "TextureBase.h" #include "RenderCommandListBase.h" -#include +#include #include @@ -81,8 +81,8 @@ bool RenderPass::Settings::operator!=(const Settings& other) const return !operator==(other); } -RenderPassBase::RenderPassBase(ContextBase& context, const Settings& settings) - : m_context(context) +RenderPassBase::RenderPassBase(RenderContextBase& context, const Settings& settings) + : m_render_context(context) , m_settings(settings) { ITT_FUNCTION_TASK(); @@ -107,7 +107,7 @@ void RenderPassBase::Begin(RenderCommandListBase& command_list) for (ColorAttachment& color_attachment : m_settings.color_attachments) { - Texture::Ptr sp_color_texture = color_attachment.wp_texture.lock(); + Ptr sp_color_texture = color_attachment.wp_texture.lock(); if (!sp_color_texture) continue; @@ -115,7 +115,7 @@ void RenderPassBase::Begin(RenderCommandListBase& command_list) color_texture.SetState(ResourceBase::State::RenderTarget, resource_transition_barriers); } - Texture::Ptr sp_depth_texture = m_settings.depth_attachment.wp_texture.lock(); + Ptr sp_depth_texture = m_settings.depth_attachment.wp_texture.lock(); if (sp_depth_texture) { TextureBase& depth_texture = dynamic_cast(*sp_depth_texture); @@ -142,10 +142,10 @@ void RenderPassBase::End(RenderCommandListBase&) m_is_begun = false; } -Resource::Refs RenderPassBase::GetColorAttachmentResources() const +Refs RenderPassBase::GetColorAttachmentResources() const { ITT_FUNCTION_TASK(); - Resource::Refs color_attach_resources; + Refs color_attach_resources; color_attach_resources.reserve(m_settings.color_attachments.size()); for (const ColorAttachment& color_attach : m_settings.color_attachments) { diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/RenderPassBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/RenderPassBase.h index cabbaded9..d87f0333b 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/RenderPassBase.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/RenderPassBase.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ Base implementation of the render pass interface. namespace Methane::Graphics { -class ContextBase; +class RenderContextBase; class RenderCommandListBase; class RenderPassBase @@ -36,7 +36,7 @@ class RenderPassBase , public std::enable_shared_from_this { public: - RenderPassBase(ContextBase& context, const Settings& settings); + RenderPassBase(RenderContextBase& context, const Settings& settings); // RenderPass interface void Update(const Settings& settings) override; @@ -46,14 +46,18 @@ class RenderPassBase virtual void Begin(RenderCommandListBase& command_list); virtual void End(RenderCommandListBase& command_list); - Ptr GetPtr() { return shared_from_this(); } - Resource::Refs GetColorAttachmentResources() const; - bool IsBegun() const { return m_is_begun; } + Ptr GetPtr() { return shared_from_this(); } + Refs GetColorAttachmentResources() const; + bool IsBegun() const { return m_is_begun; } protected: - ContextBase& m_context; - Settings m_settings; - bool m_is_begun = false; + RenderContextBase& GetRenderContext() { return m_render_context; } + const RenderContextBase& GetRenderContext() const { return m_render_context; } + +private: + RenderContextBase& m_render_context; + Settings m_settings; + bool m_is_begun = false; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/RenderStateBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/RenderStateBase.cpp index cc9f326e4..f2bb14feb 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/RenderStateBase.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/RenderStateBase.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ Base implementation of the render state interface. #include "RenderStateBase.h" -#include +#include #include @@ -154,7 +154,7 @@ RenderState::Group::Mask RenderState::Settings::Compare(const Settings& left, co return changed_state_groups; } -RenderStateBase::RenderStateBase(ContextBase& context, const Settings& settings) +RenderStateBase::RenderStateBase(RenderContextBase& context, const Settings& settings) : m_context(context) , m_settings(settings) { @@ -187,4 +187,11 @@ void RenderStateBase::SetScissorRects(const ScissorRects& scissor_rects) m_settings.scissor_rects = scissor_rects; } +Program& RenderStateBase::GetProgram() +{ + ITT_FUNCTION_TASK(); + assert(!!m_settings.sp_program); + return *m_settings.sp_program; +} + } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/RenderStateBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/RenderStateBase.h index 0eabad2b0..ea149d7d7 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/RenderStateBase.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/RenderStateBase.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ Base implementation of the render state interface. namespace Methane::Graphics { -class ContextBase; +class RenderContextBase; class RenderCommandListBase; class RenderStateBase @@ -39,10 +39,10 @@ class RenderStateBase , public std::enable_shared_from_this { public: - RenderStateBase(ContextBase& context, const Settings& settings); + RenderStateBase(RenderContextBase& context, const Settings& settings); // RenderState interface - const Settings& GetSettings() const override { return m_settings; } + const Settings& GetSettings() const override { return m_settings; } void Reset(const Settings& settings) override; void SetViewports(const Viewports& viewports) override; void SetScissorRects(const ScissorRects& scissor_rects) override; @@ -50,11 +50,15 @@ class RenderStateBase // RenderStateBase interface virtual void Apply(RenderCommandListBase& command_list, Group::Mask apply_groups) = 0; - Ptr GetPtr() { return shared_from_this(); } + Ptr GetPtr() { return shared_from_this(); } + RenderContextBase& GetRenderContext() { return m_context; } protected: - ContextBase& m_context; - Settings m_settings; + Program& GetProgram(); + +private: + RenderContextBase& m_context; + Settings m_settings; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/ResourceBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/ResourceBase.cpp index 41865ce24..fc5b2940c 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/ResourceBase.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/ResourceBase.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ Base implementation of the resource interface. #include "ContextBase.h" #include -#include +#include #include #include @@ -35,7 +35,7 @@ Base implementation of the resource interface. namespace Methane::Graphics { -Resource::Location::Location(Ptr sp_resource, Data::Size offset) +Resource::Location::Location(Ptr sp_resource, Data::Size offset) : m_sp_resource(std::move(sp_resource)) , m_offset(offset) { @@ -94,7 +94,7 @@ std::string Resource::Usage::ToString(Usage::Mask usage_mask) noexcept return names_ss.str(); } -Resource::Descriptor::Descriptor(DescriptorHeap& in_heap, int32_t in_index) +Resource::Descriptor::Descriptor(DescriptorHeap& in_heap, Data::Index in_index) : heap(in_heap) , index(in_index) { @@ -182,11 +182,10 @@ void ResourceBase::InitializeDefaultDescriptors() auto descriptor_by_usage_it = m_descriptor_by_usage.find(usage); if (descriptor_by_usage_it == m_descriptor_by_usage.end()) { - // Create deafult resource descriptor by usage + // Create default resource descriptor by usage const DescriptorHeap::Type heap_type = GetDescriptorHeapTypeByUsage(usage); - Descriptor descriptor(m_context.GetResourceManager().GetDescriptorHeap(heap_type)); - descriptor.index = descriptor.heap.AddResource(*this); - m_descriptor_by_usage.emplace(usage, descriptor); + DescriptorHeap& heap = m_context.GetResourceManager().GetDescriptorHeap(heap_type); + m_descriptor_by_usage.emplace(usage, Descriptor(heap, heap.AddResource(*this))); } } } diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/ResourceBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/ResourceBase.h index 496d0a7d6..909915b66 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/ResourceBase.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/ResourceBase.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -31,6 +31,8 @@ Base implementation of the resource interface. namespace Methane::Graphics { +class ContextBase; + class ResourceBase : public virtual Resource , public ObjectBase @@ -76,8 +78,7 @@ class ResourceBase struct ReleasePool { - using Ptr = std::shared_ptr; - static Ptr Create(); + static Ptr Create(); virtual void AddResource(ResourceBase& resource) = 0; virtual void ReleaseResources() = 0; @@ -105,7 +106,9 @@ class ResourceBase protected: DescriptorHeap::Type GetDescriptorHeapTypeByUsage(Usage::Value usage) const; const Descriptor& GetDescriptorByUsage(Usage::Value usage) const; + ContextBase& GetContext() { return m_context; } +private: const Type m_type; const Usage::Mask m_usage_mask; ContextBase& m_context; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/ResourceManager.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/ResourceManager.cpp index 9f2e3a924..e0d85a50a 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/ResourceManager.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/ResourceManager.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ and deferred releasing of GPU resource. #include "ResourceManager.h" -#include +#include #include #include @@ -46,7 +46,7 @@ void ResourceManager::Initialize(const Settings& settings) m_deferred_heap_allocation = settings.deferred_heap_allocation; for (uint32_t heap_type_idx = 0; heap_type_idx < static_cast(DescriptorHeap::Type::Count); ++heap_type_idx) { - DescriptorHeaps& desc_heaps = m_descriptor_heap_types[heap_type_idx]; + Ptrs& desc_heaps = m_descriptor_heap_types[heap_type_idx]; desc_heaps.clear(); // CPU only accessible descriptor heaps of all types are created for default resource creation @@ -56,7 +56,7 @@ void ResourceManager::Initialize(const Settings& settings) desc_heaps.push_back(DescriptorHeap::Create(m_context, heap_settings)); // GPU accessible descriptor heaps are created for program resource bindings - if (DescriptorHeap::IsShaderVisibileHeapType(heap_type)) + if (DescriptorHeap::IsShaderVisibleHeapType(heap_type)) { const uint32_t shader_visible_heap_size = settings.shader_visible_heap_sizes[heap_type_idx]; const DescriptorHeap::Settings heap_settings = { heap_type, shader_visible_heap_size, m_deferred_heap_allocation, true }; @@ -69,29 +69,29 @@ void ResourceManager::CompleteInitialization() { ITT_FUNCTION_TASK(); - std::lock_guard lock_guard(m_deferred_resource_bindings_mutex); + std::lock_guard lock_guard(m_deferred_program_bindings_mutex); - for (const DescriptorHeaps& desc_heaps : m_descriptor_heap_types) + for (const Ptrs& desc_heaps : m_descriptor_heap_types) { - for (const DescriptorHeap::Ptr& sp_desc_heap : desc_heaps) + for (const Ptr& sp_desc_heap : desc_heaps) { assert(!!sp_desc_heap); sp_desc_heap->Allocate(); } } - Data::ParallelForEach( - m_deferred_resource_bindings.begin(), m_deferred_resource_bindings.end(), - [](const Program::ResourceBindings::WeakPtr& wp_resource_bindings) + Data::ParallelForEach::const_iterator, const WeakPtr>( + m_deferred_program_bindings.begin(), m_deferred_program_bindings.end(), + [](const WeakPtr& wp_program_bindings) { - Program::ResourceBindings::Ptr sp_resource_bindings = wp_resource_bindings.lock(); - if (!sp_resource_bindings) + Ptr sp_program_bindings = wp_program_bindings.lock(); + if (!sp_program_bindings) return; - static_cast(*sp_resource_bindings).CompleteInitialization(); + static_cast(*sp_program_bindings).CompleteInitialization(); }); - m_deferred_resource_bindings.clear(); + m_deferred_program_bindings.clear(); } void ResourceManager::Release() @@ -103,18 +103,18 @@ void ResourceManager::Release() m_sp_release_pool->ReleaseResources(); } - for (DescriptorHeaps& desc_heaps : m_descriptor_heap_types) + for (Ptrs& desc_heaps : m_descriptor_heap_types) { desc_heaps.clear(); } } -void ResourceManager::DeferResourceBindingsInitialization(Program::ResourceBindings& resource_bindings) +void ResourceManager::DeferProgramBindingsInitialization(ProgramBindings& program_bindings) { ITT_FUNCTION_TASK(); - std::lock_guard lock_guard(m_deferred_resource_bindings_mutex); - m_deferred_resource_bindings.push_back(static_cast(resource_bindings).GetPtr()); + std::lock_guard lock_guard(m_deferred_program_bindings_mutex); + m_deferred_program_bindings.push_back(static_cast(program_bindings).GetPtr()); } uint32_t ResourceManager::CreateDescriptorHeap(const DescriptorHeap::Settings& settings) @@ -126,23 +126,23 @@ uint32_t ResourceManager::CreateDescriptorHeap(const DescriptorHeap::Settings& s { throw std::invalid_argument("Can not create \"Undefined\" descriptor heap."); } - DescriptorHeaps& desc_heaps = m_descriptor_heap_types[static_cast(settings.type)]; + Ptrs& desc_heaps = m_descriptor_heap_types[static_cast(settings.type)]; desc_heaps.push_back(DescriptorHeap::Create(m_context, settings)); return static_cast(desc_heaps.size() - 1); } -const DescriptorHeap::Ptr& ResourceManager::GetDescriptorHeapPtr(DescriptorHeap::Type type, uint32_t heap_index) +const Ptr& ResourceManager::GetDescriptorHeapPtr(DescriptorHeap::Type type, Data::Index heap_index) { ITT_FUNCTION_TASK(); if (type == DescriptorHeap::Type::Undefined || type == DescriptorHeap::Type::Count) { - static const DescriptorHeap::Ptr empty_ptr; - return empty_ptr; + static const Ptr s_empty_ptr; + return s_empty_ptr; } - DescriptorHeaps& desc_heaps = m_descriptor_heap_types[static_cast(type)]; + Ptrs& desc_heaps = m_descriptor_heap_types[static_cast(type)]; if (heap_index >= desc_heaps.size()) { throw std::invalid_argument("There is no \"" + DescriptorHeap::GetTypeName(type) + @@ -152,7 +152,7 @@ const DescriptorHeap::Ptr& ResourceManager::GetDescriptorHeapPtr(DescriptorHeap: return desc_heaps[heap_index]; } -DescriptorHeap& ResourceManager::GetDescriptorHeap(DescriptorHeap::Type type, uint32_t heap_index) +DescriptorHeap& ResourceManager::GetDescriptorHeap(DescriptorHeap::Type type, Data::Index heap_index) { ITT_FUNCTION_TASK(); @@ -161,7 +161,7 @@ DescriptorHeap& ResourceManager::GetDescriptorHeap(DescriptorHeap::Type type, ui { throw std::invalid_argument("Can not get reference to \"Undefined\" descriptor heap."); } - const DescriptorHeap::Ptr& sp_resource_heap = GetDescriptorHeapPtr(type, heap_index); + const Ptr& sp_resource_heap = GetDescriptorHeapPtr(type, heap_index); if (!sp_resource_heap) { throw std::invalid_argument("Descriptor heap of type \"" + DescriptorHeap::GetTypeName(type) + @@ -170,34 +170,34 @@ DescriptorHeap& ResourceManager::GetDescriptorHeap(DescriptorHeap::Type type, ui return *sp_resource_heap; } -const DescriptorHeap::Ptr& ResourceManager::GetDefaultShaderVisibleDescriptorHeapPtr(DescriptorHeap::Type type) +const Ptr& ResourceManager::GetDefaultShaderVisibleDescriptorHeapPtr(DescriptorHeap::Type type) const { ITT_FUNCTION_TASK(); if (type == DescriptorHeap::Type::Undefined || type == DescriptorHeap::Type::Count) { - static const DescriptorHeap::Ptr empty_ptr; - return empty_ptr; + static const Ptr s_empty_ptr; + return s_empty_ptr; } - const DescriptorHeaps& descriptor_heaps = m_descriptor_heap_types[static_cast(type)]; + const Ptrs& descriptor_heaps = m_descriptor_heap_types[static_cast(type)]; auto descriptor_heaps_it = std::find_if(descriptor_heaps.begin(), descriptor_heaps.end(), - [](const DescriptorHeap::Ptr& sp_descriptor_heap) + [](const Ptr& sp_descriptor_heap) { assert(sp_descriptor_heap); return sp_descriptor_heap && sp_descriptor_heap->GetSettings().shader_visible; }); - static const DescriptorHeap::Ptr empty_heap_ptr; - return descriptor_heaps_it != descriptor_heaps.end() ? *descriptor_heaps_it : empty_heap_ptr; + static const Ptr s_empty_heap_ptr; + return descriptor_heaps_it != descriptor_heaps.end() ? *descriptor_heaps_it : s_empty_heap_ptr; } -DescriptorHeap& ResourceManager::GetDefaultShaderVisibleDescriptorHeap(DescriptorHeap::Type type) +DescriptorHeap& ResourceManager::GetDefaultShaderVisibleDescriptorHeap(DescriptorHeap::Type type) const { ITT_FUNCTION_TASK(); - const DescriptorHeap::Ptr& sp_resource_heap = GetDefaultShaderVisibleDescriptorHeapPtr(type); + const Ptr& sp_resource_heap = GetDefaultShaderVisibleDescriptorHeapPtr(type); if (!sp_resource_heap) { throw std::invalid_argument("There is no shader visible descriptor heap of type \"" + DescriptorHeap::GetTypeName(type) + "\"."); @@ -212,9 +212,9 @@ ResourceManager::DescriptorHeapSizeByType ResourceManager::GetDescriptorHeapSize DescriptorHeapSizeByType descriptor_heap_sizes; for (uint32_t heap_type_idx = 0; heap_type_idx < static_cast(DescriptorHeap::Type::Count); ++heap_type_idx) { - const DescriptorHeaps& desc_heaps = m_descriptor_heap_types[heap_type_idx]; + const Ptrs& desc_heaps = m_descriptor_heap_types[heap_type_idx]; uint32_t max_heap_size = 0; - for (const DescriptorHeap::Ptr& sp_desc_heap : desc_heaps) + for (const Ptr& sp_desc_heap : desc_heaps) { assert(!!sp_desc_heap); assert(sp_desc_heap->GetSettings().type == static_cast(heap_type_idx)); @@ -234,8 +234,7 @@ ResourceBase::ReleasePool& ResourceManager::GetReleasePool() { ITT_FUNCTION_TASK(); assert(!!m_sp_release_pool); - - return static_cast(*m_sp_release_pool); + return *m_sp_release_pool; } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/ResourceManager.h b/Modules/Graphics/Core/Sources/Methane/Graphics/ResourceManager.h index 37c6b13d0..da31518d2 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/ResourceManager.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/ResourceManager.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -56,26 +56,25 @@ class ResourceManager void Release(); bool DeferredHeapAllocationEnabled() const { return m_deferred_heap_allocation; } - void DeferResourceBindingsInitialization(Program::ResourceBindings& resource_bindings); + void DeferProgramBindingsInitialization(ProgramBindings& program_bindings); uint32_t CreateDescriptorHeap(const DescriptorHeap::Settings& settings); // returns index of the created descriptor heap - const DescriptorHeap::Ptr& GetDescriptorHeapPtr(DescriptorHeap::Type type, uint32_t heap_index = 0); - DescriptorHeap& GetDescriptorHeap(DescriptorHeap::Type type, uint32_t heap_index = 0); - const DescriptorHeap::Ptr& GetDefaultShaderVisibleDescriptorHeapPtr(DescriptorHeap::Type type); - DescriptorHeap& GetDefaultShaderVisibleDescriptorHeap(DescriptorHeap::Type type); + const Ptr& GetDescriptorHeapPtr(DescriptorHeap::Type type, Data::Index heap_index = 0); + DescriptorHeap& GetDescriptorHeap(DescriptorHeap::Type type, Data::Index heap_index = 0); + const Ptr& GetDefaultShaderVisibleDescriptorHeapPtr(DescriptorHeap::Type type) const; + DescriptorHeap& GetDefaultShaderVisibleDescriptorHeap(DescriptorHeap::Type type) const; DescriptorHeapSizeByType GetDescriptorHeapSizes(bool get_allocated_size, bool for_shader_visible_heaps) const; ResourceBase::ReleasePool& GetReleasePool(); -protected: - using DescriptorHeapTypes = std::array(DescriptorHeap::Type::Count)>; - using ProgramResourceBindings = std::vector; +private: + using DescriptorHeapTypes = std::array, static_cast(DescriptorHeap::Type::Count)>; - bool m_deferred_heap_allocation = false; - ContextBase& m_context; - DescriptorHeapTypes m_descriptor_heap_types; - ResourceBase::ReleasePool::Ptr m_sp_release_pool; - ProgramResourceBindings m_deferred_resource_bindings; - std::mutex m_deferred_resource_bindings_mutex; + bool m_deferred_heap_allocation = false; + ContextBase& m_context; + DescriptorHeapTypes m_descriptor_heap_types; + Ptr m_sp_release_pool; + WeakPtrs m_deferred_program_bindings; + std::mutex m_deferred_program_bindings_mutex; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/SamplerBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/SamplerBase.cpp index e5111808a..2c9b340b3 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/SamplerBase.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/SamplerBase.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,11 +23,30 @@ Base implementation of the sampler interface. #include "SamplerBase.h" -#include +#include namespace Methane::Graphics { +Sampler::Settings::Settings(const Filter& in_filter, const Address& in_address, + const LevelOfDetail& in_lod, uint32_t in_max_anisotropy, + BorderColor in_border_color, Compare in_compare_function) + : filter(in_filter) + , address(in_address) + , lod(in_lod) + , max_anisotropy(in_max_anisotropy) + , border_color(in_border_color) + , compare_function(in_compare_function) +{ +} + +Sampler::LevelOfDetail::LevelOfDetail(float in_bias, float in_min, float in_max) + : min(in_min) + , max(in_max) + , bias(in_bias) +{ +} + SamplerBase::SamplerBase(ContextBase& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage) : ResourceNT(Type::Sampler, Usage::ShaderRead, context, descriptor_by_usage) , m_context(context) diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/SamplerBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/SamplerBase.h index 47702f836..d58ab4349 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/SamplerBase.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/SamplerBase.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -47,6 +47,9 @@ class SamplerBase Data::Size GetDataSize() const override { return 0; } protected: + ContextBase& GetContext() { return m_context; } + +private: ContextBase& m_context; Settings m_settings; }; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/ShaderBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/ShaderBase.cpp index 152feae8a..a28164010 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/ShaderBase.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/ShaderBase.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ Base implementation of the shader interface. #include "ShaderBase.h" #include "ProgramBase.h" -#include +#include #include @@ -44,84 +44,6 @@ std::string Shader::GetTypeName(Type shader_type) noexcept return "Unknown"; } -ShaderBase::ResourceBindingBase::ResourceBindingBase(ContextBase& context, const Settings& settings) - : m_context(context) - , m_settings(settings) -{ - ITT_FUNCTION_TASK(); -} - -void ShaderBase::ResourceBindingBase::SetResourceLocations(const Resource::Locations& resource_locations) -{ - ITT_FUNCTION_TASK(); - - m_resource_locations.clear(); - if (resource_locations.empty()) - throw std::invalid_argument("Can not set empty resources for resource binding."); - - const bool is_addressable_binding = IsAddressable(); - - for (const Resource::Location& resource_location : resource_locations) - { - if (resource_location.GetResource().GetResourceType() != m_settings.resource_type) - { - throw std::invalid_argument("Incompatible resource type \"" + Resource::GetTypeName(resource_location.GetResource().GetResourceType()) + - "\" is bound to argument \"" + GetArgumentName() + - "\" of type \"" + Resource::GetTypeName(m_settings.resource_type) + "\"."); - } - - const Resource::Usage::Mask resource_usage_mask = resource_location.GetResource().GetUsageMask(); - if (static_cast(resource_usage_mask & Resource::Usage::Addressable) != is_addressable_binding) - throw std::invalid_argument("Resource addressable usage flag does not match with resource binding state."); - - if (!is_addressable_binding && resource_location.GetOffset() > 0) - throw std::invalid_argument("Can not set resource location with non-zero offset to non-addressable resource binding."); - } - - m_resource_locations = resource_locations; -} - -DescriptorHeap::Type ShaderBase::ResourceBindingBase::GetDescriptorHeapType() const -{ - ITT_FUNCTION_TASK(); - return (m_settings.resource_type == Resource::Type::Sampler) - ? DescriptorHeap::Type::Samplers - : DescriptorHeap::Type::ShaderResources; -} - -bool ShaderBase::ResourceBindingBase::IsAlreadyApplied(const Program& program, const Program::Argument& program_argument, - const CommandListBase::CommandState& command_state, - bool check_binding_value_changes) const -{ - ITT_FUNCTION_TASK(); - if (!command_state.sp_resource_bindings) - return false; - - const ProgramBase::ResourceBindingsBase& previous_resource_bindings = static_cast(*command_state.sp_resource_bindings); - - if (std::addressof(previous_resource_bindings.GetProgram()) != std::addressof(program)) - return false; - - // 1) No need in setting constant resource binding - // when another binding was previously set in the same command list for the same program - if (m_settings.is_constant) - return true; - - if (!check_binding_value_changes) - return false; - - const Shader::ResourceBinding::Ptr& previous_argument_resource_binding = command_state.sp_resource_bindings->Get(program_argument); - if (!previous_argument_resource_binding) - return false; - - // 2) No need in setting resource binding to the same location - // as a previous resource binding set in the same command list for the same program - if (previous_argument_resource_binding->GetResourceLocations() == m_resource_locations) - return true; - - return false; -} - ShaderBase::ShaderBase(Type type, ContextBase& context, const Settings& settings) : m_type(type) , m_context(context) @@ -130,12 +52,6 @@ ShaderBase::ShaderBase(Type type, ContextBase& context, const Settings& settings ITT_FUNCTION_TASK(); } -uint32_t ShaderBase::GetProgramInputBufferIndexByArgumentName(const ProgramBase& program, const std::string& argument_name) const -{ - ITT_FUNCTION_TASK(); - return program.GetInputBufferIndexByArgumentName(argument_name); -} - uint32_t ShaderBase::GetProgramInputBufferIndexByArgumentSemantic(const ProgramBase& program, const std::string& argument_semantic) const { ITT_FUNCTION_TASK(); diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/ShaderBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/ShaderBase.h index cdf85dcf6..5e460567c 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/ShaderBase.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/ShaderBase.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ Base implementation of the shader interface. #include "CommandListBase.h" #include "DescriptorHeap.h" +#include "ProgramBindingsBase.h" #include @@ -40,47 +41,6 @@ class ShaderBase , public std::enable_shared_from_this { public: - class ResourceBindingBase - : public ResourceBinding - , public std::enable_shared_from_this - { - public: - struct Settings - { - Shader::Type shader_type; - std::string argument_name; - Resource::Type resource_type; - uint32_t resource_count; - bool is_constant; - bool is_addressable; - }; - - ResourceBindingBase(ContextBase& context, const Settings& settings); - ResourceBindingBase(const ResourceBindingBase& other) = default; - - // ResourceBinding interface - Shader::Type GetShaderType() const override { return m_settings.shader_type; } - const std::string& GetArgumentName() const override { return m_settings.argument_name; } - bool IsConstant() const override { return m_settings.is_constant; } - bool IsAddressable() const override { return m_settings.is_addressable; } - uint32_t GetResourceCount() const override { return m_settings.resource_count; } - const Resource::Locations& GetResourceLocations() const override { return m_resource_locations; } - void SetResourceLocations(const Resource::Locations& resource_locations) override; - - DescriptorHeap::Type GetDescriptorHeapType() const; - - Ptr GetPtr() { return shared_from_this(); } - bool HasResources() const { return !m_resource_locations.empty(); } - bool IsAlreadyApplied(const Program& program, const Program::Argument& program_argument, - const CommandListBase::CommandState& command_state, - bool check_binding_value_changes) const; - - protected: - ContextBase& m_context; - const Settings m_settings; - Resource::Locations m_resource_locations; - }; - ShaderBase(Type type, ContextBase& context, const Settings& settings); // Shader interface @@ -88,22 +48,22 @@ class ShaderBase const Settings& GetSettings() const noexcept override { return m_settings; } // ShaderBase interface - virtual ResourceBindings GetResourceBindings(const std::set& constant_argument_names, - const std::set& addressable_argument_names) const = 0; + using ArgumentBindings = Ptrs; + virtual ArgumentBindings GetArgumentBindings(const Program::ArgumentDescriptions& argument_descriptions) const = 0; - Ptr GetPtr() { return shared_from_this(); } - std::string GetTypeName() const noexcept { return Shader::GetTypeName(m_type); } + Ptr GetPtr() { return shared_from_this(); } + std::string GetTypeName() const noexcept { return Shader::GetTypeName(m_type); } protected: - uint32_t GetProgramInputBufferIndexByArgumentName(const ProgramBase& program, const std::string& argument_name) const; - uint32_t GetProgramInputBufferIndexByArgumentSemantic(const ProgramBase& program, const std::string& argument_semantic) const; - std::string GetCompiledEntryFunctionName() const; + ContextBase& GetContext() { return m_context; } + const ContextBase& GetContext() const { return m_context; } + uint32_t GetProgramInputBufferIndexByArgumentSemantic(const ProgramBase& program, const std::string& argument_semantic) const; + std::string GetCompiledEntryFunctionName() const; +private: const Type m_type; ContextBase& m_context; const Settings m_settings; }; -using Shaders = std::vector; - } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/TextureBase.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/TextureBase.cpp index 3e5d8b78a..7986e4c32 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/TextureBase.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/TextureBase.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,9 +23,9 @@ Base implementation of the texture interface. #include "TextureBase.h" #include "DescriptorHeap.h" -#include "ContextBase.h" +#include "RenderContextBase.h" -#include +#include #include diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/TextureBase.h b/Modules/Graphics/Core/Sources/Methane/Graphics/TextureBase.h index 946b91338..93486842a 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/TextureBase.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/TextureBase.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -45,6 +45,7 @@ class TextureBase uint32_t GetRequiredSubresourceCount() const; static void ValidateDimensions(DimensionType dimension_type, const Dimensions& dimensions, bool mipmapped); +private: const Settings m_settings; }; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Types.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Types.cpp index d6817d075..32bf537b1 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Types.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Types.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ Methane primitive graphics types. ******************************************************************************/ #include -#include +#include #include @@ -33,10 +33,10 @@ ScissorRect GetFrameScissorRect(const FrameRect& frame_rect) { ITT_FUNCTION_TASK(); return ScissorRect{ - ScissorRect::Point(static_cast(std::max(0, frame_rect.origin.x())), - static_cast(std::max(0, frame_rect.origin.y()))), - ScissorRect::Size(frame_rect.origin.x() >= 0 ? frame_rect.size.width : frame_rect.size.width + frame_rect.origin.x(), - frame_rect.origin.y() >= 0 ? frame_rect.size.height : frame_rect.size.height + frame_rect.origin.y()) + ScissorRect::Point(static_cast(std::max(0, frame_rect.origin.GetX())), + static_cast(std::max(0, frame_rect.origin.GetY()))), + ScissorRect::Size(frame_rect.origin.GetX() >= 0 ? frame_rect.size.width : frame_rect.size.width + frame_rect.origin.GetX(), + frame_rect.origin.GetY() >= 0 ? frame_rect.size.height : frame_rect.size.height + frame_rect.origin.GetY()) }; } @@ -53,7 +53,7 @@ Viewport GetFrameViewport(const FrameRect& frame_rect) { ITT_FUNCTION_TASK(); return Viewport{ - Viewport::Point(static_cast(frame_rect.origin.x()), static_cast(frame_rect.origin.y()), 0.0), + Viewport::Point(static_cast(frame_rect.origin.GetX()), static_cast(frame_rect.origin.GetY()), 0.0), Viewport::Size(static_cast(frame_rect.size.width), static_cast(frame_rect.size.height), 1.0) }; } diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/BlitCommandListVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/BlitCommandListVK.cpp new file mode 100644 index 000000000..e354c549b --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/BlitCommandListVK.cpp @@ -0,0 +1,89 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/BlitCommandListVK.cpp +Vulkan implementation of the blit command list interface. + +******************************************************************************/ + +#include "BlitCommandListVK.h" +#include "CommandQueueVK.h" + +#include + +#include + +namespace Methane::Graphics +{ + +Ptr BlitCommandList::Create(CommandQueue& command_queue) +{ + ITT_FUNCTION_TASK(); + return std::make_shared(static_cast(command_queue)); +} + +BlitCommandListVK::BlitCommandListVK(CommandQueueBase& command_queue) + : CommandListBase(command_queue, CommandList::Type::Blit) +{ + ITT_FUNCTION_TASK(); +} + +void BlitCommandListVK::Reset(const std::string& debug_group) +{ + ITT_FUNCTION_TASK(); +} + +void BlitCommandListVK::SetName(const std::string& name) +{ + ITT_FUNCTION_TASK(); + + CommandListBase::SetName(name); +} + +void BlitCommandListVK::PushDebugGroup(const std::string& name) +{ + ITT_FUNCTION_TASK(); +} + +void BlitCommandListVK::PopDebugGroup() +{ + ITT_FUNCTION_TASK(); +} + +void BlitCommandListVK::Commit() +{ + ITT_FUNCTION_TASK(); + + assert(!IsCommitted()); + CommandListBase::Commit(); +} + +void BlitCommandListVK::Execute(uint32_t frame_index) +{ + ITT_FUNCTION_TASK(); + + CommandListBase::Execute(frame_index); +} + +CommandQueueVK& BlitCommandListVK::GetCommandQueueVK() noexcept +{ + ITT_FUNCTION_TASK(); + return static_cast(GetCommandQueue()); +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/BlitCommandListVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/BlitCommandListVK.h new file mode 100644 index 000000000..51ee721a8 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/BlitCommandListVK.h @@ -0,0 +1,62 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/BlitCommandListVK.h +Vulkan implementation of the blit command list interface. + +******************************************************************************/ + +#pragma once + +#include +#include + +namespace Methane::Graphics +{ + +class CommandQueueVK; + +class BlitCommandListVK final + : public CommandListBase + , public BlitCommandList +{ +public: + BlitCommandListVK(CommandQueueBase& command_queue); + + // CommandList interface + void PushDebugGroup(const std::string& name) override; + void PopDebugGroup() override; + void Commit() override; + + // CommandListBase interface + void SetResourceBarriers(const ResourceBase::Barriers&) override { } + void Execute(uint32_t frame_index) override; + + // BlitCommandList interface + void Reset(const std::string& debug_group = "") override; + + // Object interface + void SetName(const std::string& label) override; + +private: + void InitializeCommandBuffer(); + + CommandQueueVK& GetCommandQueueVK() noexcept; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/BufferVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/BufferVK.cpp index 6f144cd2b..b69dee823 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/BufferVK.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/BufferVK.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,31 +22,30 @@ Vulkan implementation of the buffer interface. ******************************************************************************/ #include "BufferVK.h" -#include "ContextVK.h" -#include +#include +#include #include -#include namespace Methane::Graphics { -Buffer::Ptr Buffer::CreateVertexBuffer(Context& context, Data::Size size, Data::Size stride) +Ptr Buffer::CreateVertexBuffer(Context& context, Data::Size size, Data::Size stride) { ITT_FUNCTION_TASK(); const Buffer::Settings settings = { Buffer::Type::Vertex, Usage::Unknown, size }; - return std::make_shared(static_cast(context), settings, stride, PixelFormat::Unknown); + return std::make_shared(dynamic_cast(context), settings, stride, PixelFormat::Unknown); } -Buffer::Ptr Buffer::CreateIndexBuffer(Context& context, Data::Size size, PixelFormat format) +Ptr Buffer::CreateIndexBuffer(Context& context, Data::Size size, PixelFormat format) { ITT_FUNCTION_TASK(); const Buffer::Settings settings = { Buffer::Type::Index, Usage::Unknown, size }; - return std::make_shared(static_cast(context), settings, 0, format); + return std::make_shared(dynamic_cast(context), settings, 0, format); } -Buffer::Ptr Buffer::CreateConstantBuffer(Context& context, Data::Size size, bool addressable, const DescriptorByUsage& descriptor_by_usage) +Ptr Buffer::CreateConstantBuffer(Context& context, Data::Size size, bool addressable, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); Usage::Mask usage_mask = Usage::ShaderRead; @@ -54,7 +53,7 @@ Buffer::Ptr Buffer::CreateConstantBuffer(Context& context, Data::Size size, bool usage_mask |= Usage::Addressable; const Buffer::Settings settings = { Buffer::Type::Constant, usage_mask, size }; - return std::make_shared(static_cast(context), settings, descriptor_by_usage); + return std::make_shared(dynamic_cast(context), settings, descriptor_by_usage); } Data::Size Buffer::GetAlignedBufferSize(Data::Size size) noexcept @@ -83,7 +82,7 @@ BufferVK::BufferVK(ContextBase& context, const Settings& settings, Data::Size st BufferVK::~BufferVK() { ITT_FUNCTION_TASK(); - m_context.GetResourceManager().GetReleasePool().AddResource(*this); + GetContext().GetResourceManager().GetReleasePool().AddResource(*this); } void BufferVK::SetName(const std::string& name) diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/BufferVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/BufferVK.h index 9afa3c56c..f785a74c0 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/BufferVK.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/BufferVK.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,11 +29,9 @@ Vulkan implementation of the buffer interface. namespace Methane::Graphics { -class BufferVK : public BufferBase +class BufferVK final : public BufferBase { public: - using Ptr = std::shared_ptr; - BufferVK(ContextBase& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); BufferVK(ContextBase& context, const Settings& settings, Data::Size stride, PixelFormat format, const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); ~BufferVK() override; @@ -47,7 +45,7 @@ class BufferVK : public BufferBase // Object interface void SetName(const std::string& name) override; -protected: +private: Data::Size m_stride = 0; PixelFormat m_format = PixelFormat::Unknown; }; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/CommandQueueVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/CommandQueueVK.cpp index 17060eb42..fd4f7071d 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/CommandQueueVK.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/CommandQueueVK.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,19 +24,20 @@ Vulkan implementation of the command queue interface. #include "CommandQueueVK.h" #include "ContextVK.h" -#include +#include +#include namespace Methane::Graphics { -CommandQueue::Ptr CommandQueue::Create(Context& context) +Ptr CommandQueue::Create(Context& context) { ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context)); + return std::make_shared(dynamic_cast(context)); } CommandQueueVK::CommandQueueVK(ContextBase& context) - : CommandQueueBase(context, true) + : CommandQueueBase(context) { ITT_FUNCTION_TASK(); } @@ -44,7 +45,6 @@ CommandQueueVK::CommandQueueVK(ContextBase& context) CommandQueueVK::~CommandQueueVK() { ITT_FUNCTION_TASK(); - assert(!IsExecuting()); } void CommandQueueVK::SetName(const std::string& name) @@ -54,10 +54,10 @@ void CommandQueueVK::SetName(const std::string& name) CommandQueueBase::SetName(name); } -ContextVK& CommandQueueVK::GetContextVK() noexcept +IContextVK& CommandQueueVK::GetContextVK() noexcept { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(GetContext()); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/CommandQueueVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/CommandQueueVK.h index 6557b5250..484e0828c 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/CommandQueueVK.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/CommandQueueVK.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ namespace Methane::Graphics { class RenderPassVK; -class ContextVK; +struct IContextVK; class CommandQueueVK final : public CommandQueueBase { @@ -40,9 +40,9 @@ class CommandQueueVK final : public CommandQueueBase // Object interface void SetName(const std::string& name) override; - ContextVK& GetContextVK() noexcept; + IContextVK& GetContextVK() noexcept; -protected: +private: void Reset(); }; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ContextVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ContextVK.cpp deleted file mode 100644 index 736fb17e3..000000000 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ContextVK.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/****************************************************************************** - -Copyright 2019 Evgeny Gorodetskiy - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -******************************************************************************* - -FILE: Methane/Graphics/Vulkan/ContextVK.mm -Vulkan implementation of the context interface. - -******************************************************************************/ - -#include "ContextVK.h" -#include "DeviceVK.h" -#include "CommandQueueVK.h" -#include "TypesVK.h" - -#include - -namespace Methane::Graphics -{ - -Context::Ptr Context::Create(const Platform::AppEnvironment& env, Device& device, const Context::Settings& settings) -{ - ITT_FUNCTION_TASK(); - return std::make_shared(env, static_cast(device), settings); -} - -ContextVK::ContextVK(const Platform::AppEnvironment& env, DeviceBase& device, const Context::Settings& settings) - : ContextBase(device, settings) -{ - ITT_FUNCTION_TASK(); - m_resource_manager.Initialize({ true }); -} - -ContextVK::~ContextVK() -{ - ITT_FUNCTION_TASK(); -} - -void ContextVK::Release() -{ - ITT_FUNCTION_TASK(); - - ContextBase::Release(); -} - -void ContextVK::Initialize(Device& device, bool deferred_heap_allocation) -{ - ITT_FUNCTION_TASK(); - - ContextBase::Initialize(device, deferred_heap_allocation); -} - -bool ContextVK::ReadyToRender() const -{ - ITT_FUNCTION_TASK(); - return true; -} - -void ContextVK::OnCommandQueueCompleted(CommandQueue& /*cmd_queue*/, uint32_t /*frame_index*/) -{ - ITT_FUNCTION_TASK(); -} - -void ContextVK::WaitForGpu(WaitFor wait_for) -{ - ITT_FUNCTION_TASK(); - - ContextBase::WaitForGpu(wait_for); - - // TODO: Wait for GPU work complete - - ContextBase::OnGpuWaitComplete(wait_for); - - if (wait_for == WaitFor::FramePresented) - { - m_frame_buffer_index = (m_frame_buffer_index + 1) % m_settings.frame_buffers_count; - } -} - -void ContextVK::Resize(const FrameSize& frame_size) -{ - ITT_FUNCTION_TASK(); - ContextBase::Resize(frame_size); -} - -void ContextVK::Present() -{ - ITT_FUNCTION_TASK(); - OnCpuPresentComplete(); -} - -bool ContextVK::SetVSyncEnabled(bool vsync_enabled) -{ - ITT_FUNCTION_TASK(); - return ContextBase::SetVSyncEnabled(vsync_enabled); -} - -bool ContextVK::SetFrameBuffersCount(uint32_t frame_buffers_count) -{ - ITT_FUNCTION_TASK(); - return ContextBase::SetFrameBuffersCount(frame_buffers_count); -} - -DeviceVK& ContextVK::GetDeviceVK() -{ - ITT_FUNCTION_TASK(); - return static_cast(GetDevice()); -} - -} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ContextVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ContextVK.h index 18585323c..74f4edfd5 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ContextVK.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ContextVK.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,45 +16,25 @@ limitations under the License. ******************************************************************************* -FILE: Methane/Graphics/Vulkan/ContextVK.h -Vulkan implementation of the context interface. +FILE: Methane/Graphics/Metal/ContextMT.h +Vulkan context accessor interface for template class ContextMT ******************************************************************************/ #pragma once -#include +#include namespace Methane::Graphics { -struct CommandQueue; -class RenderPassVK; class DeviceVK; +class CommandQueueVK; -class ContextVK : public ContextBase +struct IContextVK { -public: - ContextVK(const Platform::AppEnvironment& env, DeviceBase& device, const Settings& settings); - ~ContextVK() override; - - // Context interface - bool ReadyToRender() const override; - void OnCommandQueueCompleted(CommandQueue& cmd_queue, uint32_t frame_index) override; - void WaitForGpu(WaitFor wait_for) override; - void Resize(const FrameSize& frame_size) override; - void Present() override; - bool SetVSyncEnabled(bool vsync_enabled) override; - bool SetFrameBuffersCount(uint32_t frame_buffers_count) override; - Platform::AppView GetAppView() const override { return { nullptr }; } - float GetContentScalingFactor() const override { return 1.f; } - - DeviceVK& GetDeviceVK(); - -protected: - // ContextBase overrides - void Release() override; - void Initialize(Device& device, bool deferred_heap_allocation) override; + virtual DeviceVK& GetDeviceVK() noexcept = 0; + virtual CommandQueueVK& GetUploadCommandQueueVK() noexcept = 0; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ContextVK.hpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ContextVK.hpp new file mode 100644 index 000000000..4975e5787 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ContextVK.hpp @@ -0,0 +1,95 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/ContextVK.hpp +Vulkan template implementation of the base context interface. + +******************************************************************************/ + +#pragma once + +#include "ContextVK.h" +#include "DeviceVK.h" + +#include +#include +#include + +#include +#include + +namespace Methane::Graphics +{ + +struct CommandQueue; + +template>> +class ContextVK : public ContextBaseT +{ +public: + ContextVK(DeviceBase& device, const typename ContextBaseT::Settings& settings) + : ContextBaseT(device, settings) + { + ITT_FUNCTION_TASK(); + } + + ~ContextVK() override + { + ITT_FUNCTION_TASK(); + } + + // Context interface + + void WaitForGpu(Context::WaitFor wait_for) override + { + ITT_FUNCTION_TASK(); + ContextBase::WaitForGpu(wait_for); + // ... + ContextBase::OnGpuWaitComplete(wait_for); + } + + // ContextBase interface + + void Initialize(DeviceBase& device, bool deferred_heap_allocation) override + { + ITT_FUNCTION_TASK(); + ContextBase::Initialize(device, deferred_heap_allocation); + } + + void Release() override + { + ITT_FUNCTION_TASK(); + ContextBase::Release(); + } + + // IContextVK interface + + DeviceVK& GetDeviceVK() noexcept override + { + ITT_FUNCTION_TASK(); + return dynamic_cast(ContextBase::GetDeviceBase()); + } + + CommandQueueVK& GetUploadCommandQueueVK() noexcept override + { + ITT_FUNCTION_TASK(); + return dynamic_cast(ContextBase::GetUploadCommandQueue()); + } +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/DescriptorHeapVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/DescriptorHeapVK.cpp index ddad37911..761024124 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/DescriptorHeapVK.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/DescriptorHeapVK.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,12 +23,12 @@ Vulkan "dummy" implementation of the descriptor heap. #include "DescriptorHeapVK.h" -#include +#include namespace Methane::Graphics { -DescriptorHeap::Ptr DescriptorHeap::Create(ContextBase& context, const Settings& settings) +Ptr DescriptorHeap::Create(ContextBase& context, const Settings& settings) { ITT_FUNCTION_TASK(); return std::make_shared(context, settings); diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/DescriptorHeapVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/DescriptorHeapVK.h index 82e156418..e73116674 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/DescriptorHeapVK.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/DescriptorHeapVK.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ namespace Methane::Graphics class ContextBase; -class DescriptorHeapVK : public DescriptorHeap +class DescriptorHeapVK final : public DescriptorHeap { public: DescriptorHeapVK(ContextBase& context, const Settings& settings); diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/DeviceVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/DeviceVK.cpp index ec15927a1..a71e9b3b9 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/DeviceVK.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/DeviceVK.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ Vulkan implementation of the device interface. #include "DeviceVK.h" -#include +#include namespace Methane::Graphics { @@ -51,14 +51,12 @@ SystemVK::~SystemVK() ITT_FUNCTION_TASK(); } -const Devices& SystemVK::UpdateGpuDevices(Device::Feature::Mask supported_features) +const Ptrs& SystemVK::UpdateGpuDevices(Device::Feature::Mask supported_features) { ITT_FUNCTION_TASK(); - - m_supported_features = supported_features; - m_devices.clear(); - - return m_devices; + SetGpuSupportedFeatures(supported_features); + ClearDevices(); + return GetGpuDevices(); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/DeviceVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/DeviceVK.h index 4dbee7106..a95745a67 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/DeviceVK.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/DeviceVK.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -41,7 +41,7 @@ class SystemVK final : public SystemBase ~SystemVK() override; void CheckForChanges() override {} - const Devices& UpdateGpuDevices(Device::Feature::Mask supported_features) override; + const Ptrs& UpdateGpuDevices(Device::Feature::Mask supported_features) override; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/FenceVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/FenceVK.cpp new file mode 100644 index 000000000..246366c84 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/FenceVK.cpp @@ -0,0 +1,92 @@ +/****************************************************************************** + +Copyright 2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Vulkan/FenceVK.cpp +Vulkan fence implementation. + +******************************************************************************/ + +#include "FenceVK.h" +#include "CommandQueueVK.h" +#include "DeviceVK.h" + +#include +#include + +#include + +namespace Methane::Graphics +{ + +UniquePtr Fence::Create(CommandQueue& command_queue) +{ + ITT_FUNCTION_TASK(); + return std::make_unique(static_cast(command_queue)); +} + +FenceVK::FenceVK(CommandQueueBase& command_queue) + : FenceBase(command_queue) +{ + ITT_FUNCTION_TASK(); + + // TODO: create native fence object +} + +FenceVK::~FenceVK() +{ + ITT_FUNCTION_TASK(); + + // TODO: release native fence object +} + +void FenceVK::Signal() +{ + ITT_FUNCTION_TASK(); + + FenceBase::Signal(); + + // TODO: signal native fence object +} + +void FenceVK::Wait() +{ + ITT_FUNCTION_TASK(); + + FenceBase::Wait(); + + // TODO: wait for native fence object +} + +void FenceVK::SetName(const std::string& name) noexcept +{ + ITT_FUNCTION_TASK(); + if (ObjectBase::GetName() == name) + return; + + ObjectBase::SetName(name); + + // TODO: set name of native fence object +} + +CommandQueueVK& FenceVK::GetCommandQueueVK() +{ + ITT_FUNCTION_TASK(); + return static_cast(GetCommandQueue()); +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/FenceVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/FenceVK.h new file mode 100644 index 000000000..bc05ed78e --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/FenceVK.h @@ -0,0 +1,52 @@ +/****************************************************************************** + +Copyright 2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Vulkan/FenceVK.h +Vulkan fence implementation. + +******************************************************************************/ + +#pragma once + +#include + +namespace Methane::Graphics +{ + +class CommandQueueVK; + +class FenceVK final : public FenceBase +{ +public: + FenceVK(CommandQueueBase& command_queue); + ~FenceVK(); + + // Fence overrides + void Signal() override; + void Wait() override; + + // Object override + void SetName(const std::string& name) noexcept override; + +private: + CommandQueueVK& GetCommandQueueVK(); + + // TODO: native fence object +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ParallelRenderCommandListVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ParallelRenderCommandListVK.cpp index 0ff50044b..962c2945e 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ParallelRenderCommandListVK.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ParallelRenderCommandListVK.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,12 +26,14 @@ Vulkan implementation of the render command list interface. #include "CommandQueueVK.h" #include "ContextVK.h" -#include +#include + +#include namespace Methane::Graphics { -ParallelRenderCommandList::Ptr ParallelRenderCommandList::Create(CommandQueue& command_queue, RenderPass& render_pass) +Ptr ParallelRenderCommandList::Create(CommandQueue& command_queue, RenderPass& render_pass) { ITT_FUNCTION_TASK(); return std::make_shared(static_cast(command_queue), static_cast(render_pass)); @@ -50,20 +52,19 @@ void ParallelRenderCommandListVK::SetName(const std::string& name) ParallelRenderCommandListBase::SetName(name); } -void ParallelRenderCommandListVK::Reset(const RenderState::Ptr& sp_render_state, const std::string& debug_group) +void ParallelRenderCommandListVK::Reset(const Ptr& sp_render_state, const std::string& debug_group) { ITT_FUNCTION_TASK(); ParallelRenderCommandListBase::Reset(sp_render_state, debug_group); } -void ParallelRenderCommandListVK::Commit(bool present_drawable) +void ParallelRenderCommandListVK::Commit() { ITT_FUNCTION_TASK(); assert(!IsCommitted()); - - ParallelRenderCommandListBase::Commit(present_drawable); + ParallelRenderCommandListBase::Commit(); } void ParallelRenderCommandListVK::Execute(uint32_t frame_index) @@ -76,7 +77,7 @@ void ParallelRenderCommandListVK::Execute(uint32_t frame_index) CommandQueueVK& ParallelRenderCommandListVK::GetCommandQueueVK() noexcept { ITT_FUNCTION_TASK(); - return static_cast(*m_sp_command_queue); + return static_cast(GetCommandQueue()); } RenderPassVK& ParallelRenderCommandListVK::GetPassVK() diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ParallelRenderCommandListVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ParallelRenderCommandListVK.h index 29f1629bf..ba1cf2fe0 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ParallelRenderCommandListVK.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ParallelRenderCommandListVK.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -35,15 +35,13 @@ class RenderPassVK; class ParallelRenderCommandListVK final : public ParallelRenderCommandListBase { public: - using Ptr = std::shared_ptr; - ParallelRenderCommandListVK(CommandQueueBase& command_queue, RenderPassBase& render_pass); // ParallelRenderCommandList interface - void Reset(const RenderState::Ptr& sp_render_state, const std::string& debug_group = "") override; + void Reset(const Ptr& sp_render_state, const std::string& debug_group = "") override; // CommandList interface - void Commit(bool present_drawable) override; + void Commit() override; // CommandListBase interface void Execute(uint32_t frame_index) override; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ProgramBindingsVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ProgramBindingsVK.cpp new file mode 100644 index 000000000..d133c4a12 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ProgramBindingsVK.cpp @@ -0,0 +1,91 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Vulkan/ProgramVK.h +Vulkan implementation of the program interface. + +******************************************************************************/ + +#include "ProgramBindingsVK.h" +#include "RenderCommandListVK.h" + +#include + +namespace Methane::Graphics +{ + +Ptr ProgramBindings::Create(const Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument) +{ + ITT_FUNCTION_TASK(); + return std::make_shared(sp_program, resource_locations_by_argument); +} + +Ptr ProgramBindings::CreateCopy(const ProgramBindings& other_program_bindings, const ResourceLocationsByArgument& replace_resource_location_by_argument) +{ + ITT_FUNCTION_TASK(); + return std::make_shared(static_cast(other_program_bindings), replace_resource_location_by_argument); +} + +Ptr ProgramBindingsBase::ArgumentBindingBase::CreateCopy(const ArgumentBindingBase& other_argument_binding) +{ + ITT_FUNCTION_TASK(); + return std::make_shared(static_cast(other_argument_binding)); +} + +ProgramBindingsVK::ArgumentBindingVK::ArgumentBindingVK(const ContextBase& context, SettingsVK settings) + : ArgumentBindingBase(context, settings) + , m_settings_vk(std::move(settings)) +{ + ITT_FUNCTION_TASK(); +} + +void ProgramBindingsVK::ArgumentBindingVK::SetResourceLocations(const Resource::Locations& resource_locations) +{ + ITT_FUNCTION_TASK(); + + ArgumentBindingBase::SetResourceLocations(resource_locations); +} + +ProgramBindingsVK::ProgramBindingsVK(const Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument) + : ProgramBindingsBase(sp_program, resource_locations_by_argument) +{ + ITT_FUNCTION_TASK(); +} + +ProgramBindingsVK::ProgramBindingsVK(const ProgramBindingsVK& other_program_bindings, const ResourceLocationsByArgument& replace_resource_location_by_argument) + : ProgramBindingsBase(other_program_bindings, replace_resource_location_by_argument) +{ + ITT_FUNCTION_TASK(); +} + +void ProgramBindingsVK::Apply(CommandListBase& command_list, ApplyBehavior::Mask apply_behavior) const +{ + ITT_FUNCTION_TASK(); + + RenderCommandListVK& vulkan_command_list = static_cast(command_list); + + for(const auto& binding_by_argument : GetArgumentBindings()) + { + const ProgramBindingsVK::ArgumentBindingVK& vulkan_argument_binding = static_cast(*binding_by_argument.second); + if ((apply_behavior & ApplyBehavior::ConstantOnce || apply_behavior & ApplyBehavior::ChangesOnly) && vulkan_command_list.GetProgramBindings() && + vulkan_argument_binding.IsAlreadyApplied(GetProgram(), *vulkan_command_list.GetProgramBindings(), apply_behavior & ApplyBehavior::ChangesOnly)) + continue; + } +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ProgramBindingsVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ProgramBindingsVK.h new file mode 100644 index 000000000..b8ffb1e7b --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ProgramBindingsVK.h @@ -0,0 +1,63 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Vulkan/ProgramVK.h +Vulkan implementation of the program interface. + +******************************************************************************/ + +#pragma once + +#include + +namespace Methane::Graphics +{ + +class ProgramBindingsVK final : public ProgramBindingsBase +{ +public: + class ArgumentBindingVK final : public ArgumentBindingBase + { + public: + struct SettingsVK : Settings + { + }; + + ArgumentBindingVK(const ContextBase& context, SettingsVK settings); + ArgumentBindingVK(const ArgumentBindingVK& other) = default; + + // ArgumentBinding interface + void SetResourceLocations(const Resource::Locations& resource_locations) override; + + const SettingsVK& GetSettingsVK() const noexcept { return m_settings_vk; } + + private: + const SettingsVK m_settings_vk; + }; + + ProgramBindingsVK(const Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument); + ProgramBindingsVK(const ProgramBindingsVK& other_program_bindings, const ResourceLocationsByArgument& replace_resource_location_by_argument); + + // ProgramBindings interface + void Apply(CommandListBase& command_list, ApplyBehavior::Mask apply_behavior) const override; + + // ProgramBindingsBase interface + void CompleteInitialization() override { } +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ProgramVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ProgramVK.cpp index 11e27feaa..533c8a25c 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ProgramVK.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ProgramVK.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -27,73 +27,22 @@ Vulkan implementation of the program interface. #include "ContextVK.h" #include "RenderCommandListVK.h" -#include - -#include +#include +#include namespace Methane::Graphics { -Program::ResourceBindings::Ptr Program::ResourceBindings::Create(const Program::Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument) -{ - ITT_FUNCTION_TASK(); - return std::make_shared(sp_program, resource_locations_by_argument); -} - -Program::ResourceBindings::Ptr Program::ResourceBindings::CreateCopy(const ResourceBindings& other_resource_bingings, const ResourceLocationsByArgument& replace_resource_location_by_argument) -{ - ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(other_resource_bingings), replace_resource_location_by_argument); -} - -ProgramVK::ResourceBindingsVK::ResourceBindingsVK(const Program::Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument) - : ResourceBindingsBase(sp_program, resource_locations_by_argument) -{ - ITT_FUNCTION_TASK(); -} - -ProgramVK::ResourceBindingsVK::ResourceBindingsVK(const ResourceBindingsVK& other_resource_bindings, const ResourceLocationsByArgument& replace_resource_location_by_argument) - : ResourceBindingsBase(other_resource_bindings, replace_resource_location_by_argument) +Ptr Program::Create(Context& context, const Settings& settings) { ITT_FUNCTION_TASK(); -} - -void ProgramVK::ResourceBindingsVK::Apply(CommandList& command_list, ApplyBehavior::Mask apply_behavior) const -{ - ITT_FUNCTION_TASK(); - - RenderCommandListVK& vulkan_command_list = dynamic_cast(command_list); - const CommandListBase::CommandState& command_state = vulkan_command_list.GetCommandState(); - - for(const auto& resource_binding_by_argument : m_resource_binding_by_argument) - { - const Argument& program_argument = resource_binding_by_argument.first; - const ShaderVK::ResourceBindingVK& vulkan_resource_binding = static_cast(*resource_binding_by_argument.second); - - if ((apply_behavior & ApplyBehavior::ConstantOnce || apply_behavior & ApplyBehavior::ChangesOnly) && - vulkan_resource_binding.IsAlreadyApplied(*m_sp_program, program_argument, command_state, apply_behavior & ApplyBehavior::ChangesOnly)) - continue; - } -} - -Program::Ptr Program::Create(Context& context, const Settings& settings) -{ - ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context), settings); + return std::make_shared(dynamic_cast(context), settings); } ProgramVK::ProgramVK(ContextBase& context, const Settings& settings) : ProgramBase(context, settings) { ITT_FUNCTION_TASK(); - - // In case if RT pixel formats are not set, we assume it renders to frame buffer - // NOTE: even when program has no pixel shaders render, render state must have at least one color format to be valid - std::vector color_formats = settings.color_formats; - if (color_formats.empty()) - { - color_formats.push_back(context.GetSettings().color_format); - } } ProgramVK::~ProgramVK() @@ -101,10 +50,10 @@ ProgramVK::~ProgramVK() ITT_FUNCTION_TASK(); } -ContextVK& ProgramVK::GetContextVK() noexcept +IContextVK& ProgramVK::GetContextVK() noexcept { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(GetContext()); } ShaderVK& ProgramVK::GetShaderVK(Shader::Type shader_type) noexcept diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ProgramVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ProgramVK.h index 80f276286..85d83d1b3 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ProgramVK.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ProgramVK.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,32 +28,19 @@ Vulkan implementation of the program interface. namespace Methane::Graphics { -class ContextVK; +struct IContextVK; class ShaderVK; -class ProgramVK : public ProgramBase +class ProgramVK final : public ProgramBase { public: - class ResourceBindingsVK : public ResourceBindingsBase - { - public: - ResourceBindingsVK(const Program::Ptr& sp_program, const ResourceLocationsByArgument& resource_locations_by_argument); - ResourceBindingsVK(const ResourceBindingsVK& other_resource_bindings, const ResourceLocationsByArgument& replace_resource_location_by_argument); - - // ResourceBindings interface - void Apply(CommandList& command_list, ApplyBehavior::Mask apply_behavior) const override; - - // ResourceBindingsBase interface - void CompleteInitialization() override { } - }; - ProgramVK(ContextBase& context, const Settings& settings); ~ProgramVK() override; ShaderVK& GetShaderVK(Shader::Type shader_type) noexcept; protected: - ContextVK& GetContextVK() noexcept; + IContextVK& GetContextVK() noexcept; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderCommandListVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderCommandListVK.cpp index debb40bec..859c96d40 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderCommandListVK.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderCommandListVK.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,18 +29,20 @@ Vulkan implementation of the render command list interface. #include "ContextVK.h" #include "BufferVK.h" -#include +#include + +#include namespace Methane::Graphics { -RenderCommandList::Ptr RenderCommandList::Create(CommandQueue& command_queue, RenderPass& render_pass) +Ptr RenderCommandList::Create(CommandQueue& command_queue, RenderPass& render_pass) { ITT_FUNCTION_TASK(); return std::make_shared(static_cast(command_queue), static_cast(render_pass)); } -RenderCommandList::Ptr RenderCommandList::Create(ParallelRenderCommandList& parallel_render_command_list) +Ptr RenderCommandList::Create(ParallelRenderCommandList& parallel_render_command_list) { ITT_FUNCTION_TASK(); return std::make_shared(static_cast(parallel_render_command_list)); @@ -58,11 +60,11 @@ RenderCommandListVK::RenderCommandListVK(ParallelRenderCommandListBase& parallel ITT_FUNCTION_TASK(); } -void RenderCommandListVK::Reset(const RenderState::Ptr& sp_render_state, const std::string& debug_group) +void RenderCommandListVK::Reset(const Ptr& sp_render_state, const std::string& debug_group) { ITT_FUNCTION_TASK(); - RenderCommandListBase::ResetDrawState(); + RenderCommandListBase::ResetCommandState(); RenderCommandListBase::Reset(sp_render_state, debug_group); } @@ -83,13 +85,13 @@ void RenderCommandListVK::PopDebugGroup() ITT_FUNCTION_TASK(); } -void RenderCommandListVK::SetVertexBuffers(const Buffer::Refs& vertex_buffers) +void RenderCommandListVK::SetVertexBuffers(const Refs& vertex_buffers) { ITT_FUNCTION_TASK(); RenderCommandListBase::SetVertexBuffers(vertex_buffers); - if (!m_draw_state.flags.vertex_buffers_changed) + if (!GetDrawingState().flags.vertex_buffers_changed) return; uint32_t vb_index = 0; @@ -124,13 +126,13 @@ void RenderCommandListVK::Draw(Primitive primitive, uint32_t vertex_count, uint3 RenderCommandListBase::Draw(primitive, vertex_count, start_vertex, instance_count, start_instance); } -void RenderCommandListVK::Commit(bool present_drawable) +void RenderCommandListVK::Commit() { ITT_FUNCTION_TASK(); assert(!IsCommitted()); - RenderCommandListBase::Commit(present_drawable); + RenderCommandListBase::Commit(); } void RenderCommandListVK::Execute(uint32_t frame_index) @@ -143,7 +145,7 @@ void RenderCommandListVK::Execute(uint32_t frame_index) CommandQueueVK& RenderCommandListVK::GetCommandQueueVK() noexcept { ITT_FUNCTION_TASK(); - return static_cast(*m_sp_command_queue); + return static_cast(GetCommandQueue()); } RenderPassVK& RenderCommandListVK::GetPassVK() diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderCommandListVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderCommandListVK.h index 2c3968d97..56f46ef82 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderCommandListVK.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderCommandListVK.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -43,15 +43,15 @@ class RenderCommandListVK final : public RenderCommandListBase // CommandList interface void PushDebugGroup(const std::string& name) override; void PopDebugGroup() override; - void Commit(bool present_drawable) override; + void Commit() override; // CommandListBase interface void SetResourceBarriers(const ResourceBase::Barriers&) override { } void Execute(uint32_t frame_index) override; // RenderCommandList interface - void Reset(const RenderState::Ptr& sp_render_state, const std::string& debug_group = "") override; - void SetVertexBuffers(const Buffer::Refs& vertex_buffers) override; + void Reset(const Ptr& sp_render_state, const std::string& debug_group = "") override; + void SetVertexBuffers(const Refs& vertex_buffers) override; void DrawIndexed(Primitive primitive, Buffer& index_buffer, uint32_t index_count, uint32_t start_index, uint32_t start_vertex, uint32_t instance_count, uint32_t start_instance) override; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderContextVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderContextVK.cpp new file mode 100644 index 000000000..089fb1b4c --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderContextVK.cpp @@ -0,0 +1,114 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/RenderContextVK.mm +Vulkan implementation of the render context interface. + +******************************************************************************/ + +#include "RenderContextVK.h" +#include "DeviceVK.h" +#include "RenderStateVK.h" +#include "CommandQueueVK.h" +#include "TypesVK.h" + +#include + +namespace Methane::Graphics +{ + +Ptr RenderContext::Create(const Platform::AppEnvironment& env, Device& device, const RenderContext::Settings& settings) +{ + ITT_FUNCTION_TASK(); + return std::make_shared(env, static_cast(device), settings); +} + +RenderContextVK::RenderContextVK(const Platform::AppEnvironment& env, DeviceBase& device, const RenderContext::Settings& settings) + : ContextVK(device, settings) +{ + ITT_FUNCTION_TASK(); +} + +RenderContextVK::~RenderContextVK() +{ + ITT_FUNCTION_TASK(); +} + +void RenderContextVK::Release() +{ + ITT_FUNCTION_TASK(); + ContextVK::Release(); +} + +void RenderContextVK::Initialize(DeviceBase& device, bool deferred_heap_allocation) +{ + ITT_FUNCTION_TASK(); + ContextVK::Initialize(device, deferred_heap_allocation); +} + +bool RenderContextVK::ReadyToRender() const +{ + ITT_FUNCTION_TASK(); + return true; +} + +void RenderContextVK::WaitForGpu(Context::WaitFor wait_for) +{ + ITT_FUNCTION_TASK(); + ContextVK::WaitForGpu(wait_for); +} + +void RenderContextVK::Resize(const FrameSize& frame_size) +{ + ITT_FUNCTION_TASK(); + ContextVK::Resize(frame_size); +} + +void RenderContextVK::Present() +{ + ITT_FUNCTION_TASK(); + ContextVK::Present(); + // ... + ContextVK::OnCpuPresentComplete(); +} + +bool RenderContextVK::SetVSyncEnabled(bool vsync_enabled) +{ + ITT_FUNCTION_TASK(); + return false; +} + +bool RenderContextVK::SetFrameBuffersCount(uint32_t frame_buffers_count) +{ + ITT_FUNCTION_TASK(); + return false; +} + +float RenderContextVK::GetContentScalingFactor() const +{ + ITT_FUNCTION_TASK(); + return 1.f; +} + +CommandQueueVK& RenderContextVK::GetRenderCommandQueueVK() +{ + ITT_FUNCTION_TASK(); + return static_cast(ContextVK::GetRenderCommandQueue()); +} + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderContextVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderContextVK.h new file mode 100644 index 000000000..81d4d98e4 --- /dev/null +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderContextVK.h @@ -0,0 +1,59 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/Metal/RenderContextVK.hh +Vulkan implementation of the render context interface. + +******************************************************************************/ + +#pragma once + +#include "ContextVK.hpp" + +#include +#include + +namespace Methane::Graphics +{ + +class RenderContextVK final : public ContextVK +{ +public: + RenderContextVK(const Platform::AppEnvironment& env, DeviceBase& device, const RenderContext::Settings& settings); + ~RenderContextVK() override; + + // Context interface + void WaitForGpu(Context::WaitFor wait_for) override; + + // RenderContext interface + bool ReadyToRender() const override; + void Resize(const FrameSize& frame_size) override; + void Present() override; + bool SetVSyncEnabled(bool vsync_enabled) override; + bool SetFrameBuffersCount(uint32_t frame_buffers_count) override; + float GetContentScalingFactor() const override; + Platform::AppView GetAppView() const override { return { }; } + + // ContextBase overrides + void Initialize(DeviceBase& device, bool deferred_heap_allocation) override; + void Release() override; + + CommandQueueVK& GetRenderCommandQueueVK(); +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderPassVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderPassVK.cpp index 1dedbfc0c..03062bc11 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderPassVK.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderPassVK.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,31 +25,29 @@ Vulkan implementation of the render pass interface. #include "ContextVK.h" #include "TextureVK.h" -#include +#include +#include namespace Methane::Graphics { -RenderPass::Ptr RenderPass::Create(Context& context, const Settings& settings) +Ptr RenderPass::Create(RenderContext& context, const Settings& settings) { ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context), settings); + return std::make_shared(dynamic_cast(context), settings); } -RenderPassVK::RenderPassVK(ContextBase& context, const Settings& settings) +RenderPassVK::RenderPassVK(RenderContextBase& context, const Settings& settings) : RenderPassBase(context, settings) { ITT_FUNCTION_TASK(); - Reset(); } void RenderPassVK::Update(const Settings& settings) { ITT_FUNCTION_TASK(); - - m_settings = settings; - + RenderPassBase::Update(settings); Reset(); } @@ -58,7 +56,7 @@ void RenderPassVK::Reset() ITT_FUNCTION_TASK(); uint32_t color_attach_index = 0; - for(ColorAttachment& color_attach : m_settings.color_attachments) + for(const ColorAttachment& color_attach : GetSettings().color_attachments) { if (color_attach.wp_texture.expired()) { @@ -75,10 +73,10 @@ void RenderPassVK::Reset() } } -ContextVK& RenderPassVK::GetContextVK() noexcept +IContextVK& RenderPassVK::GetContextVK() noexcept { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(GetRenderContext()); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderPassVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderPassVK.h index a689f5890..9ce831031 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderPassVK.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderPassVK.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,12 +28,12 @@ Vulkan implementation of the render pass interface. namespace Methane::Graphics { -class ContextVK; +struct IContextVK; -class RenderPassVK : public RenderPassBase +class RenderPassVK final : public RenderPassBase { public: - RenderPassVK(ContextBase& context, const Settings& settings); + RenderPassVK(RenderContextBase& context, const Settings& settings); // RenderPass interface void Update(const Settings& settings) override; @@ -41,7 +41,7 @@ class RenderPassVK : public RenderPassBase void Reset(); protected: - ContextVK& GetContextVK() noexcept; + IContextVK& GetContextVK() noexcept; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderStateVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderStateVK.cpp index 72251af0b..1384b178b 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderStateVK.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderStateVK.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,20 +29,19 @@ Vulkan implementation of the render state interface. #include "ShaderVK.h" #include "TypesVK.h" -#include - -#include +#include +#include namespace Methane::Graphics { -RenderState::Ptr RenderState::Create(Context& context, const RenderState::Settings& state_settings) +Ptr RenderState::Create(RenderContext& context, const RenderState::Settings& state_settings) { ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context), state_settings); + return std::make_shared(dynamic_cast(context), state_settings); } -RenderStateVK::RenderStateVK(ContextBase& context, const Settings& settings) +RenderStateVK::RenderStateVK(RenderContextBase& context, const Settings& settings) : RenderStateBase(context, settings) { ITT_FUNCTION_TASK(); @@ -63,16 +62,16 @@ void RenderStateVK::Reset(const Settings& settings) } RenderStateBase::Reset(settings); - - ProgramVK& vulkan_program = static_cast(*m_settings.sp_program); - if (!m_settings.viewports.empty()) + ProgramVK& vulkan_program = static_cast(*settings.sp_program); + + if (!settings.viewports.empty()) { - SetViewports(m_settings.viewports); + SetViewports(settings.viewports); } - if (!m_settings.scissor_rects.empty()) + if (!settings.scissor_rects.empty()) { - SetScissorRects(m_settings.scissor_rects); + SetScissorRects(settings.scissor_rects); } ResetNativeState(); @@ -111,10 +110,10 @@ void RenderStateVK::ResetNativeState() ITT_FUNCTION_TASK(); } -ContextVK& RenderStateVK::GetContextVK() noexcept +IContextVK& RenderStateVK::GetContextVK() noexcept { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(GetRenderContext()); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderStateVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderStateVK.h index 0fa5f2262..fc80949dc 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderStateVK.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/RenderStateVK.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,12 +30,12 @@ Vulkan implementation of the render state interface. namespace Methane::Graphics { -class ContextVK; +struct IContextVK; -class RenderStateVK : public RenderStateBase +class RenderStateVK final : public RenderStateBase { public: - RenderStateVK(ContextBase& context, const Settings& settings); + RenderStateVK(RenderContextBase& context, const Settings& settings); ~RenderStateVK() override; // RenderState interface @@ -50,7 +50,7 @@ class RenderStateVK : public RenderStateBase void SetName(const std::string& name) override; protected: - ContextVK& GetContextVK() noexcept; + IContextVK& GetContextVK() noexcept; void ResetNativeState(); }; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ResourceVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ResourceVK.cpp index 98ce7102a..24d5bda1a 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ResourceVK.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ResourceVK.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,8 @@ Vulkan implementation of the resource interface. #include "ResourceVK.h" #include "ContextVK.h" -#include +#include +#include namespace Methane::Graphics { @@ -33,7 +34,7 @@ struct ResourceContainerVK { }; -ResourceBase::ReleasePool::Ptr ResourceBase::ReleasePool::Create() +Ptr ResourceBase::ReleasePool::Create() { ITT_FUNCTION_TASK(); return std::make_shared(); @@ -63,10 +64,10 @@ ResourceVK::ResourceVK(Type type, Usage::Mask usage_mask, ContextBase& context, ITT_FUNCTION_TASK(); } -ContextVK& ResourceVK::GetContextVK() noexcept +IContextVK& ResourceVK::GetContextVK() noexcept { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(GetContext()); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ResourceVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ResourceVK.h index 08ad2a281..7272f27ba 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ResourceVK.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ResourceVK.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,15 +30,13 @@ Vulkan implementation of the resource interface. namespace Methane::Graphics { -class ContextVK; +struct IContextVK; struct ResourceContainerVK; class ResourceVK : public ResourceBase { public: - using Ptr = std::shared_ptr; - - class ReleasePoolVK : public ReleasePool + class ReleasePoolVK final : public ReleasePool { public: ReleasePoolVK(); @@ -54,7 +52,7 @@ class ResourceVK : public ResourceBase ResourceVK(Type type, Usage::Mask usage_mask, ContextBase& context, const DescriptorByUsage& descriptor_by_usage); protected: - ContextVK& GetContextVK() noexcept; + IContextVK& GetContextVK() noexcept; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/SamplerVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/SamplerVK.cpp index bb1ffb9ee..9ca4c8130 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/SamplerVK.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/SamplerVK.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,15 +24,16 @@ Vulkan implementation of the sampler interface. #include "SamplerVK.h" #include "ContextVK.h" -#include +#include +#include namespace Methane::Graphics { -Sampler::Ptr Sampler::Create(Context& context, const Sampler::Settings& settings, const DescriptorByUsage& descriptor_by_usage) +Ptr Sampler::Create(Context& context, const Sampler::Settings& settings, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context), settings, descriptor_by_usage); + return std::make_shared(dynamic_cast(context), settings, descriptor_by_usage); } SamplerVK::SamplerVK(ContextBase& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage) @@ -42,7 +43,7 @@ SamplerVK::SamplerVK(ContextBase& context, const Settings& settings, const Descr InitializeDefaultDescriptors(); - ResetSampletState(); + ResetSamplerState(); } SamplerVK::~SamplerVK() @@ -56,18 +57,18 @@ void SamplerVK::SetName(const std::string& name) SamplerBase::SetName(name); - ResetSampletState(); + ResetSamplerState(); } -void SamplerVK::ResetSampletState() +void SamplerVK::ResetSamplerState() { ITT_FUNCTION_TASK(); } -ContextVK& SamplerVK::GetContextVK() noexcept +IContextVK& SamplerVK::GetContextVK() noexcept { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(GetContext()); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/SamplerVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/SamplerVK.h index 5c2165c21..71dc1d84b 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/SamplerVK.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/SamplerVK.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,9 +28,9 @@ Vulkan implementation of the sampler interface. namespace Methane::Graphics { -class ContextVK; +struct IContextVK; -class SamplerVK : public SamplerBase +class SamplerVK final : public SamplerBase { public: SamplerVK(ContextBase& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage); @@ -40,9 +40,9 @@ class SamplerVK : public SamplerBase void SetName(const std::string& name) override; protected: - void ResetSampletState(); + void ResetSamplerState(); - ContextVK& GetContextVK() noexcept; + IContextVK& GetContextVK() noexcept; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ShaderVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ShaderVK.cpp index ff4364c03..e79d5043d 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ShaderVK.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ShaderVK.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,38 +24,19 @@ Vulkan implementation of the shader interface. #include "ShaderVK.h" #include "ContextVK.h" -#include +#include +#include namespace Methane::Graphics { -Shader::ResourceBinding::Ptr Shader::ResourceBinding::CreateCopy(const ResourceBinding& other_resource_binging) +Ptr Shader::Create(Shader::Type shader_type, Context& context, const Settings& settings) { ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(other_resource_binging)); + return std::make_shared(shader_type, dynamic_cast(context), settings); } -ShaderVK::ResourceBindingVK::ResourceBindingVK(ContextBase& context, const Settings& settings) - : ResourceBindingBase(context, settings.base) - , m_settings(settings) -{ - ITT_FUNCTION_TASK(); -} - -void ShaderVK::ResourceBindingVK::SetResourceLocations(const Resource::Locations& resource_locations) -{ - ITT_FUNCTION_TASK(); - - ShaderBase::ResourceBindingBase::SetResourceLocations(resource_locations); -} - -Shader::Ptr Shader::Create(Shader::Type shader_type, Context& context, const Settings& settings) -{ - ITT_FUNCTION_TASK(); - return std::make_shared(shader_type, static_cast(context), settings); -} - -ShaderVK::ShaderVK(Shader::Type shader_type, ContextVK& context, const Settings& settings) +ShaderVK::ShaderVK(Shader::Type shader_type, ContextBase& context, const Settings& settings) : ShaderBase(shader_type, context, settings) { ITT_FUNCTION_TASK(); @@ -66,21 +47,17 @@ ShaderVK::~ShaderVK() ITT_FUNCTION_TASK(); } -ShaderBase::ResourceBindings ShaderVK::GetResourceBindings(const std::set& constant_argument_names, - const std::set& addressable_argument_names) const +ShaderBase::ArgumentBindings ShaderVK::GetArgumentBindings(const Program::ArgumentDescriptions&) const { ITT_FUNCTION_TASK(); - - ShaderBase::ResourceBindings resource_bindings; - return resource_bindings; - - return resource_bindings; + ArgumentBindings argument_bindings; + return argument_bindings; } -ContextVK& ShaderVK::GetContextVK() noexcept +IContextVK& ShaderVK::GetContextVK() noexcept { ITT_FUNCTION_TASK(); - return static_cast(m_context); + return static_cast(GetContext()); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ShaderVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ShaderVK.h index 194366493..5fd10c696 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ShaderVK.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/ShaderVK.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -31,42 +31,20 @@ Vulkan implementation of the shader interface. namespace Methane::Graphics { -class ContextVK; +struct IContextVK; class ProgramVK; -class ShaderVK : public ShaderBase +class ShaderVK final : public ShaderBase { public: - class ResourceBindingVK : public ResourceBindingBase - { - public: - struct Settings - { - ResourceBindingBase::Settings base; - }; - - ResourceBindingVK(ContextBase& context, const Settings& settings); - ResourceBindingVK(const ResourceBindingVK& other) = default; - - // ResourceBinding interface - void SetResourceLocations(const Resource::Locations& resource_locations) override; - uint32_t GetResourceCount() const override { return 1; } - - const Settings& GetSettings() const noexcept { return m_settings; } - - protected: - const Settings m_settings; - }; - - ShaderVK(Shader::Type shader_type, ContextVK& context, const Settings& settings); + ShaderVK(Shader::Type shader_type, ContextBase& context, const Settings& settings); ~ShaderVK() override; // ShaderBase interface - ResourceBindings GetResourceBindings(const std::set& constant_argument_names, - const std::set& addressable_argument_names) const override; + ArgumentBindings GetArgumentBindings(const Program::ArgumentDescriptions& argument_descriptions) const override; protected: - ContextVK& GetContextVK() noexcept; + IContextVK& GetContextVK() noexcept; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/TextureVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/TextureVK.cpp index b0f8bfb6c..3afd72837 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/TextureVK.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/TextureVK.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,52 +22,51 @@ Vulkan implementation of the texture interface. ******************************************************************************/ #include "TextureVK.h" -#include "ContextVK.h" #include "RenderCommandListVK.h" #include "TypesVK.h" -#include +#include +#include #include -#include namespace Methane::Graphics { -Texture::Ptr Texture::CreateRenderTarget(Context& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage) +Ptr Texture::CreateRenderTarget(RenderContext& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); - return std::make_shared(static_cast(context), settings, descriptor_by_usage); + return std::make_shared(dynamic_cast(context), settings, descriptor_by_usage); } -Texture::Ptr Texture::CreateFrameBuffer(Context& context, uint32_t /*frame_buffer_index*/, const DescriptorByUsage& descriptor_by_usage) +Ptr Texture::CreateFrameBuffer(RenderContext& context, uint32_t /*frame_buffer_index*/, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); - const Context::Settings& context_settings = context.GetSettings(); + const RenderContext::Settings& context_settings = context.GetSettings(); const Settings texture_settings = Settings::FrameBuffer(context_settings.frame_size, context_settings.color_format); - return std::make_shared(static_cast(context), texture_settings, descriptor_by_usage); + return std::make_shared(dynamic_cast(context), texture_settings, descriptor_by_usage); } -Texture::Ptr Texture::CreateDepthStencilBuffer(Context& context, const DescriptorByUsage& descriptor_by_usage) +Ptr Texture::CreateDepthStencilBuffer(RenderContext& context, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); - const Context::Settings& context_settings = context.GetSettings(); + const RenderContext::Settings& context_settings = context.GetSettings(); const Settings texture_settings = Settings::DepthStencilBuffer(context_settings.frame_size, context_settings.depth_stencil_format); - return std::make_shared(static_cast(context), texture_settings, descriptor_by_usage); + return std::make_shared(dynamic_cast(context), texture_settings, descriptor_by_usage); } -Texture::Ptr Texture::CreateImage(Context& context, const Dimensions& dimensions, uint32_t array_length, PixelFormat pixel_format, bool mipmapped, const DescriptorByUsage& descriptor_by_usage) +Ptr Texture::CreateImage(Context& context, const Dimensions& dimensions, uint32_t array_length, PixelFormat pixel_format, bool mipmapped, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); const Settings texture_settings = Settings::Image(dimensions, array_length, pixel_format, mipmapped, Usage::ShaderRead); - return std::make_shared(static_cast(context), texture_settings, descriptor_by_usage); + return std::make_shared(dynamic_cast(context), texture_settings, descriptor_by_usage); } -Texture::Ptr Texture::CreateCube(Context& context, uint32_t dimension_size, uint32_t array_length, PixelFormat pixel_format, bool mipmapped, const DescriptorByUsage& descriptor_by_usage) +Ptr Texture::CreateCube(Context& context, uint32_t dimension_size, uint32_t array_length, PixelFormat pixel_format, bool mipmapped, const DescriptorByUsage& descriptor_by_usage) { ITT_FUNCTION_TASK(); const Settings texture_settings = Settings::Cube(dimension_size, array_length, pixel_format, mipmapped, Usage::ShaderRead); - return std::make_shared(static_cast(context), texture_settings, descriptor_by_usage); + return std::make_shared(dynamic_cast(context), texture_settings, descriptor_by_usage); } TextureVK::TextureVK(ContextBase& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage) @@ -82,9 +81,9 @@ TextureVK::~TextureVK() { ITT_FUNCTION_TASK(); - if (m_settings.type != Texture::Type::FrameBuffer) + if (GetSettings().type != Texture::Type::FrameBuffer) { - m_context.GetResourceManager().GetReleasePool().AddResource(*this); + GetContext().GetResourceManager().GetReleasePool().AddResource(*this); } } @@ -104,7 +103,7 @@ void TextureVK::SetData(const SubResources& sub_resources) throw std::invalid_argument("Can not set texture data from empty sub-resources."); } - if (m_settings.mipmapped && sub_resources.size() < GetRequiredSubresourceCount()) + if (GetSettings().mipmapped && sub_resources.size() < GetRequiredSubresourceCount()) { GenerateMipLevels(); } @@ -120,7 +119,7 @@ void TextureVK::UpdateFrameBuffer() { ITT_FUNCTION_TASK(); - if (m_settings.type != Texture::Type::FrameBuffer) + if (GetSettings().type != Texture::Type::FrameBuffer) { throw std::logic_error("Unable to update frame buffer on non-FB texture."); } diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/TextureVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/TextureVK.h index a25f9322f..43d819bc6 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/TextureVK.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/TextureVK.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,11 +28,9 @@ Vulkan implementation of the texture interface. namespace Methane::Graphics { -class TextureVK : public TextureBase +class TextureVK final : public TextureBase { public: - using Ptr = std::shared_ptr; - TextureVK(ContextBase& context, const Settings& settings, const DescriptorByUsage& descriptor_by_usage = DescriptorByUsage()); ~TextureVK() override; diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/TypesVK.cpp b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/TypesVK.cpp index a7612d6ba..2e975cb1b 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/TypesVK.cpp +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/TypesVK.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,16 +17,12 @@ limitations under the License. ******************************************************************************* FILE: Methane/Graphics/Vulkan/TypesVK.mm -Methane graphics types convertors to Vulkan native types. +Methane graphics types converters to Vulkan native types. ******************************************************************************/ #include "TypesVK.h" -#include - -#include - namespace Methane::Graphics { diff --git a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/TypesVK.h b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/TypesVK.h index ad8a751c3..899472d73 100644 --- a/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/TypesVK.h +++ b/Modules/Graphics/Core/Sources/Methane/Graphics/Vulkan/TypesVK.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ limitations under the License. ******************************************************************************* FILE: Methane/Graphics/Vulkan/TypesVK.h -Methane graphics types convertors to Vulkan native types. +Methane graphics types converters to Vulkan native types. ******************************************************************************/ diff --git a/Modules/Graphics/Extensions/CMakeLists.txt b/Modules/Graphics/Extensions/CMakeLists.txt index 632c91f33..115b30cd3 100644 --- a/Modules/Graphics/Extensions/CMakeLists.txt +++ b/Modules/Graphics/Extensions/CMakeLists.txt @@ -36,13 +36,14 @@ add_library(${TARGET} STATIC ${SOURCES} ) -add_methane_shaders(${TARGET} "${HLSL_SOURCES}") +add_methane_shaders(${TARGET} "${HLSL_SOURCES}" "6_0") add_methane_embedded_textures(${TARGET} "${IMAGES_DIR}" "${TEXTURES}") target_link_libraries(${TARGET} + MethaneCommonPrimitives MethanePlatformUtils MethaneGraphicsCore - MethaneDataInstrumentation + MethaneInstrumentation ) if (METHANE_USE_OPEN_IMAGE_IO) diff --git a/Modules/Graphics/Extensions/Include/Methane/Graphics/Extensions.h b/Modules/Graphics/Extensions/Include/Methane/Graphics/Extensions.h index 14a8b893c..7fec6d043 100644 --- a/Modules/Graphics/Extensions/Include/Methane/Graphics/Extensions.h +++ b/Modules/Graphics/Extensions/Include/Methane/Graphics/Extensions.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Extensions/Include/Methane/Graphics/ImageLoader.h b/Modules/Graphics/Extensions/Include/Methane/Graphics/ImageLoader.h index 6c8a2167c..6e6103c77 100644 --- a/Modules/Graphics/Extensions/Include/Methane/Graphics/ImageLoader.h +++ b/Modules/Graphics/Extensions/Include/Methane/Graphics/ImageLoader.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -66,8 +66,8 @@ class ImageLoader final ImageData LoadImage(const std::string& image_path, size_t channels_count, bool create_copy); - Texture::Ptr LoadImageToTexture2D(Context& context, const std::string& image_path, bool mipmapped); - Texture::Ptr LoadImagesToTextureCube(Context& context, const CubeFaceResources& image_paths, bool mipmapped); + Ptr LoadImageToTexture2D(Context& context, const std::string& image_path, bool mipmapped); + Ptr LoadImagesToTextureCube(Context& context, const CubeFaceResources& image_paths, bool mipmapped); private: Data::Provider& m_data_provider; diff --git a/Modules/Graphics/Extensions/Include/Methane/Graphics/LogoBadge.h b/Modules/Graphics/Extensions/Include/Methane/Graphics/LogoBadge.h index 2bfd8c6cf..41dde6cc3 100644 --- a/Modules/Graphics/Extensions/Include/Methane/Graphics/LogoBadge.h +++ b/Modules/Graphics/Extensions/Include/Methane/Graphics/LogoBadge.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -35,8 +35,6 @@ class ImageLoader; class LogoBadge : public ScreenQuad { public: - using Ptr = std::shared_ptr; - enum class FrameCorner : uint32_t { TopLeft = 0u, @@ -60,8 +58,8 @@ class LogoBadge : public ScreenQuad { } }; - LogoBadge(Context& context, Settings settings = Settings()); - LogoBadge(Context& context, Texture::Ptr sp_texture, Settings settings = Settings()); + LogoBadge(RenderContext& context, Settings settings = Settings()); + LogoBadge(RenderContext& context, Ptr sp_texture, Settings settings = Settings()); void Resize(const FrameSize& frame_size); diff --git a/Modules/Graphics/Extensions/Include/Methane/Graphics/MeshBuffers.hpp b/Modules/Graphics/Extensions/Include/Methane/Graphics/MeshBuffers.hpp index 25b4fe3c4..102da2f9e 100644 --- a/Modules/Graphics/Extensions/Include/Methane/Graphics/MeshBuffers.hpp +++ b/Modules/Graphics/Extensions/Include/Methane/Graphics/MeshBuffers.hpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -31,9 +31,9 @@ Mesh buffers with texture extension structure. #include #include #include -#include +#include #include -#include +#include #include #include @@ -46,20 +46,16 @@ namespace Methane::Graphics struct MeshBufferBindings { - using ResourceBindingsArray = std::vector; - - Buffer::Ptr sp_uniforms_buffer; - ResourceBindingsArray resource_bindings_per_instance; + Ptr sp_uniforms_buffer; + Ptrs program_bindings_per_instance; }; template class MeshBuffers { public: - using Ptr = std::unique_ptr>; - template - MeshBuffers(Context& context, const BaseMesh& mesh_data, const std::string& mesh_name, const Mesh::Subsets& mesh_subsets = Mesh::Subsets()) + MeshBuffers(RenderContext& context, const BaseMesh& mesh_data, const std::string& mesh_name, const Mesh::Subsets& mesh_subsets = Mesh::Subsets()) : m_mesh_name(mesh_name) , m_mesh_subsets(!mesh_subsets.empty() ? mesh_subsets : Mesh::Subsets{ Mesh::Subset(mesh_data.GetType(), { 0, mesh_data.GetVertexCount() }, @@ -90,7 +86,7 @@ class MeshBuffers } template - MeshBuffers(Context& context, const UberMesh& uber_mesh_data, const std::string& mesh_name) + MeshBuffers(RenderContext& context, const UberMesh& uber_mesh_data, const std::string& mesh_name) : MeshBuffers(context, uber_mesh_data, mesh_name, uber_mesh_data.GetSubsets()) { ITT_FUNCTION_TASK(); @@ -98,7 +94,7 @@ class MeshBuffers virtual ~MeshBuffers() = default; - void Draw(RenderCommandList& cmd_list, Program::ResourceBindings& resource_bindings, + void Draw(RenderCommandList& cmd_list, ProgramBindings& program_bindings, uint32_t mesh_subset_index = 0, uint32_t instance_count = 1, uint32_t start_instance = 0) { ITT_FUNCTION_TASK(); @@ -107,7 +103,7 @@ class MeshBuffers throw std::invalid_argument("Can not draw mesh subset because its index is out of bounds."); const Mesh::Subset& mesh_subset = m_mesh_subsets[mesh_subset_index]; - cmd_list.SetResourceBindings(resource_bindings); + cmd_list.SetProgramBindings(program_bindings); cmd_list.SetVertexBuffers({ GetVertexBuffer() }); cmd_list.DrawIndexed(RenderCommandList::Primitive::Triangle, GetIndexBuffer(), mesh_subset.indices.count, mesh_subset.indices.offset, @@ -115,15 +111,15 @@ class MeshBuffers instance_count, start_instance); } - void Draw(RenderCommandList& cmd_list, const MeshBufferBindings::ResourceBindingsArray& instance_resource_bindings, uint32_t first_instance_index = 0) + void Draw(RenderCommandList& cmd_list, const Ptrs& instance_program_bindings, uint32_t first_instance_index = 0) { - Draw(cmd_list, instance_resource_bindings.begin(), instance_resource_bindings.end(), first_instance_index); + Draw(cmd_list, instance_program_bindings.begin(), instance_program_bindings.end(), first_instance_index); } void Draw(RenderCommandList& cmd_list, - const MeshBufferBindings::ResourceBindingsArray::const_iterator& instance_resource_bindings_begin, - const MeshBufferBindings::ResourceBindingsArray::const_iterator& instance_resource_bindings_end, - Program::ResourceBindings::ApplyBehavior::Mask bindings_apply_behavior = Program::ResourceBindings::ApplyBehavior::AllIncremental, + const Ptrs::const_iterator& instance_program_bindings_begin, + const Ptrs::const_iterator& instance_program_bindings_end, + ProgramBindings::ApplyBehavior::Mask bindings_apply_behavior = ProgramBindings::ApplyBehavior::AllIncremental, uint32_t first_instance_index = 0) { ITT_FUNCTION_TASK(); @@ -131,22 +127,22 @@ class MeshBuffers cmd_list.SetVertexBuffers({ GetVertexBuffer() }); Buffer& index_buffer = GetIndexBuffer(); - for (MeshBufferBindings::ResourceBindingsArray::const_iterator instance_resource_bindings_it = instance_resource_bindings_begin; - instance_resource_bindings_it != instance_resource_bindings_end; - ++instance_resource_bindings_it) + for (Ptrs::const_iterator instance_program_bindings_it = instance_program_bindings_begin; + instance_program_bindings_it != instance_program_bindings_end; + ++instance_program_bindings_it) { - const Program::ResourceBindings::Ptr& sp_resource_bindings = *instance_resource_bindings_it; + const Ptr& sp_program_bindings = *instance_program_bindings_it; - if (!sp_resource_bindings) + if (!sp_program_bindings) throw std::invalid_argument("Can not set Null resource bindings"); - const uint32_t instance_index = first_instance_index + static_cast(std::distance(instance_resource_bindings_begin, instance_resource_bindings_it)); + const uint32_t instance_index = first_instance_index + static_cast(std::distance(instance_program_bindings_begin, instance_program_bindings_it)); const uint32_t subset_index = GetSubsetByInstanceIndex(instance_index); assert(subset_index < m_mesh_subsets.size()); const Mesh::Subset& mesh_subset = m_mesh_subsets[subset_index]; - cmd_list.SetResourceBindings(*sp_resource_bindings, bindings_apply_behavior); + cmd_list.SetProgramBindings(*sp_program_bindings, bindings_apply_behavior); cmd_list.DrawIndexed(RenderCommandList::Primitive::Triangle, index_buffer, mesh_subset.indices.count, mesh_subset.indices.offset, mesh_subset.indices_adjusted ? 0 : mesh_subset.vertices.offset, @@ -154,26 +150,26 @@ class MeshBuffers } } - void DrawParallel(ParallelRenderCommandList& parallel_cmd_list, const MeshBufferBindings::ResourceBindingsArray& instance_resource_bindings, - Program::ResourceBindings::ApplyBehavior::Mask bindings_apply_behavior = Program::ResourceBindings::ApplyBehavior::AllIncremental) + void DrawParallel(ParallelRenderCommandList& parallel_cmd_list, const Ptrs& instance_program_bindings, + ProgramBindings::ApplyBehavior::Mask bindings_apply_behavior = ProgramBindings::ApplyBehavior::AllIncremental) { ITT_FUNCTION_TASK(); - const RenderCommandList::Ptrs& render_cmd_lists = parallel_cmd_list.GetParallelCommandLists(); - const uint32_t instances_count_per_command_list = static_cast(Data::DivCeil(instance_resource_bindings.size(), render_cmd_lists.size())); + const Ptrs& render_cmd_lists = parallel_cmd_list.GetParallelCommandLists(); + const uint32_t instances_count_per_command_list = static_cast(Data::DivCeil(instance_program_bindings.size(), render_cmd_lists.size())); Data::ParallelFor(0u, render_cmd_lists.size(), [&](size_t cl_index) { - const RenderCommandList::Ptr& sp_render_command_list = render_cmd_lists[cl_index]; + const Ptr& sp_render_command_list = render_cmd_lists[cl_index]; const uint32_t begin_instance_index = static_cast(cl_index * instances_count_per_command_list); const uint32_t end_instance_index = std::min(begin_instance_index + instances_count_per_command_list, - static_cast(instance_resource_bindings.size())); + static_cast(instance_program_bindings.size())); assert(!!sp_render_command_list); Draw(*sp_render_command_list, - instance_resource_bindings.begin() + begin_instance_index, - instance_resource_bindings.begin() + end_instance_index, + instance_program_bindings.begin() + begin_instance_index, + instance_program_bindings.begin() + end_instance_index, bindings_apply_behavior, begin_instance_index); }); } @@ -242,8 +238,8 @@ class MeshBuffers const std::string m_mesh_name; const Mesh::Subsets m_mesh_subsets; - Buffer::Ptr m_sp_vertex; - Buffer::Ptr m_sp_index; + Ptr m_sp_vertex; + Ptr m_sp_index; InstanceUniforms m_final_pass_instance_uniforms; // Actual uniforms buffers are created separately in Frame dependent resources }; @@ -251,11 +247,8 @@ template class TexturedMeshBuffers : public MeshBuffers { public: - using Ptr = std::unique_ptr>; - template - TexturedMeshBuffers(Context& context, const BaseMesh& mesh_data, - const std::string& mesh_name) + TexturedMeshBuffers(RenderContext& context, const BaseMesh& mesh_data, const std::string& mesh_name) : MeshBuffers(context, mesh_data, mesh_name) { ITT_FUNCTION_TASK(); @@ -263,14 +256,20 @@ class TexturedMeshBuffers : public MeshBuffers } template - TexturedMeshBuffers(Context& context, const UberMesh& uber_mesh_data, const std::string& mesh_name) + TexturedMeshBuffers(RenderContext& context, const UberMesh& uber_mesh_data, const std::string& mesh_name) : MeshBuffers(context, uber_mesh_data, mesh_name) { ITT_FUNCTION_TASK(); m_subset_textures.resize(MeshBuffers::GetSubsetsCount()); } - const Texture::Ptr& GetSubsetTexturePtr(uint32_t subset_index = 0) const + const Ptr& GetTexturePtr() const + { + ITT_FUNCTION_TASK(); + return GetSubsetTexturePtr(0); + } + + const Ptr& GetSubsetTexturePtr(uint32_t subset_index) const { ITT_FUNCTION_TASK(); @@ -280,7 +279,7 @@ class TexturedMeshBuffers : public MeshBuffers return m_subset_textures[subset_index]; } - const Texture::Ptr& GetInstanceTexturePtr(uint32_t instance_index = 0) const + const Ptr& GetInstanceTexturePtr(uint32_t instance_index = 0) const { ITT_FUNCTION_TASK(); @@ -288,7 +287,7 @@ class TexturedMeshBuffers : public MeshBuffers return GetSubsetTexturePtr(subset_index); } - void SetTexture(const Texture::Ptr& sp_texture) + void SetTexture(const Ptr& sp_texture) { ITT_FUNCTION_TASK(); @@ -300,7 +299,7 @@ class TexturedMeshBuffers : public MeshBuffers } } - void SetSubsetTexture(const Texture::Ptr& sp_texture, uint32_t subset_index) + void SetSubsetTexture(const Ptr& sp_texture, uint32_t subset_index) { ITT_FUNCTION_TASK(); @@ -311,7 +310,7 @@ class TexturedMeshBuffers : public MeshBuffers } protected: - using Textures = std::vector; + using Textures = std::vector>; private: Textures m_subset_textures; diff --git a/Modules/Graphics/Extensions/Include/Methane/Graphics/ScreenQuad.h b/Modules/Graphics/Extensions/Include/Methane/Graphics/ScreenQuad.h index 7b2d23428..070b34e33 100644 --- a/Modules/Graphics/Extensions/Include/Methane/Graphics/ScreenQuad.h +++ b/Modules/Graphics/Extensions/Include/Methane/Graphics/ScreenQuad.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,11 +23,12 @@ ScreenQuad rendering primitive. #pragma once -#include +#include #include #include #include #include +#include #include #include #include @@ -42,8 +43,6 @@ struct RenderCommandList; class ScreenQuad { public: - using Ptr = std::shared_ptr; - struct Settings { const std::string name; @@ -52,7 +51,7 @@ class ScreenQuad Color4f blend_color = Color4f(1.f, 1.f, 1.f, 1.f); }; - ScreenQuad(Context& context, Texture::Ptr sp_texture, Settings settings); + ScreenQuad(RenderContext& context, Ptr sp_texture, Settings settings); void SetBlendColor(const Color4f& blend_color); void SetScreenRect(const FrameRect& screen_rect); @@ -63,15 +62,15 @@ class ScreenQuad private: void UpdateConstantsBuffer() const; - Settings m_settings; - const std::string m_debug_region_name; - RenderState::Ptr m_sp_state; - Buffer::Ptr m_sp_vertex_buffer; - Buffer::Ptr m_sp_index_buffer; - Buffer::Ptr m_sp_const_buffer; - Texture::Ptr m_sp_texture; - Sampler::Ptr m_sp_texture_sampler; - Program::ResourceBindings::Ptr m_sp_const_resource_bindings; + Settings m_settings; + const std::string m_debug_region_name; + Ptr m_sp_state; + Ptr m_sp_vertex_buffer; + Ptr m_sp_index_buffer; + Ptr m_sp_const_buffer; + Ptr m_sp_texture; + Ptr m_sp_texture_sampler; + Ptr m_sp_const_program_bindings; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Extensions/Include/Methane/Graphics/SkyBox.h b/Modules/Graphics/Extensions/Include/Methane/Graphics/SkyBox.h index e6db7b671..e1903e4cc 100644 --- a/Modules/Graphics/Extensions/Include/Methane/Graphics/SkyBox.h +++ b/Modules/Graphics/Extensions/Include/Methane/Graphics/SkyBox.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ SkyBox rendering primitive #include "ImageLoader.h" #include "MeshBuffers.hpp" -#include +#include #include #include #include @@ -43,8 +43,6 @@ namespace Methane::Graphics class SkyBox { public: - using Ptr = std::shared_ptr; - struct Settings { const Camera& view_camera; @@ -61,21 +59,30 @@ class SkyBox SHADER_FIELD_ALIGN Matrix44f mvp_matrix; }; - SkyBox(Context& context, ImageLoader& image_loader, const Settings& settings); + SkyBox(RenderContext& context, ImageLoader& image_loader, const Settings& settings); - Program::ResourceBindings::Ptr CreateResourceBindings(const Buffer::Ptr& sp_uniforms_buffer); + Ptr CreateProgramBindings(const Ptr& sp_uniforms_buffer); void Resize(const FrameSize& frame_size); void Update(); void Draw(RenderCommandList& cmd_list, MeshBufferBindings& buffer_bindings); private: - using TheTexturedMeshBuffers = TexturedMeshBuffers; + struct Vertex + { + Mesh::Position position; + + inline static const Mesh::VertexLayout layout = { + Mesh::VertexField::Position, + }; + }; + + SkyBox(RenderContext& context, ImageLoader& image_loader, const Settings& settings, BaseMesh mesh); - Settings m_settings; - Context& m_context; - TheTexturedMeshBuffers m_mesh_buffers; - Sampler::Ptr m_sp_texture_sampler; - RenderState::Ptr m_sp_state; + Settings m_settings; + RenderContext& m_context; + TexturedMeshBuffers m_mesh_buffers; + Ptr m_sp_texture_sampler; + Ptr m_sp_state; }; } // namespace Methane::Graphics diff --git a/Modules/Graphics/Extensions/Shaders/ScreenQuad.hlsl b/Modules/Graphics/Extensions/Shaders/ScreenQuad.hlsl index 6c477192d..1638a6805 100644 --- a/Modules/Graphics/Extensions/Shaders/ScreenQuad.hlsl +++ b/Modules/Graphics/Extensions/Shaders/ScreenQuad.hlsl @@ -1,3 +1,26 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: MethaneKit/Modules/Graphics/Extensions/Shaders/ScreenQuad.hlsl +Shaders for screen quad rendering with 2D texture + +******************************************************************************/ + struct VSInput { float3 position : POSITION; diff --git a/Modules/Graphics/Extensions/Shaders/SkyBox.hlsl b/Modules/Graphics/Extensions/Shaders/SkyBox.hlsl index 7fcd0835e..a58656148 100644 --- a/Modules/Graphics/Extensions/Shaders/SkyBox.hlsl +++ b/Modules/Graphics/Extensions/Shaders/SkyBox.hlsl @@ -1,3 +1,26 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: MethaneKit/Modules/Graphics/Extensions/Shaders/SkyBox.hlsl +Shaders for sky-box rendering from cube-map texture on a sphere mesh without lighting + +******************************************************************************/ + struct VSInput { float3 position : POSITION; diff --git a/Modules/Graphics/Extensions/Sources/Methane/Graphics/ImageLoader.cpp b/Modules/Graphics/Extensions/Sources/Methane/Graphics/ImageLoader.cpp index dbe4d8549..606e86379 100644 --- a/Modules/Graphics/Extensions/Sources/Methane/Graphics/ImageLoader.cpp +++ b/Modules/Graphics/Extensions/Sources/Methane/Graphics/ImageLoader.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ by decoding them from popular image formats. #include #include -#include +#include #include #ifdef USE_OPEN_IMAGE_IO @@ -148,18 +148,18 @@ ImageLoader::ImageData ImageLoader::LoadImage(const std::string& image_path, siz #endif } -Texture::Ptr ImageLoader::LoadImageToTexture2D(Context& context, const std::string& image_path, bool mipmapped) +Ptr ImageLoader::LoadImageToTexture2D(Context& context, const std::string& image_path, bool mipmapped) { ITT_FUNCTION_TASK(); const ImageData image_data = LoadImage(image_path, 4, false); - Texture::Ptr sp_texture = Texture::CreateImage(context, image_data.dimensions, 1, PixelFormat::RGBA8Unorm, mipmapped); + Ptr sp_texture = Texture::CreateImage(context, image_data.dimensions, 1, PixelFormat::RGBA8Unorm, mipmapped); sp_texture->SetData({ { image_data.pixels.p_data, image_data.pixels.size } }); return sp_texture; } -Texture::Ptr ImageLoader::LoadImagesToTextureCube(Context& context, const CubeFaceResources& image_paths, bool mipmapped) +Ptr ImageLoader::LoadImagesToTextureCube(Context& context, const CubeFaceResources& image_paths, bool mipmapped) { ITT_FUNCTION_TASK(); @@ -210,7 +210,7 @@ Texture::Ptr ImageLoader::LoadImagesToTextureCube(Context& context, const CubeFa // Load face images to cube texture - Texture::Ptr sp_texture = Texture::CreateCube(context, face_dimensions.width, 1, PixelFormat::RGBA8Unorm, mipmapped); + Ptr sp_texture = Texture::CreateCube(context, face_dimensions.width, 1, PixelFormat::RGBA8Unorm, mipmapped); sp_texture->SetData(face_resources); return sp_texture; diff --git a/Modules/Graphics/Extensions/Sources/Methane/Graphics/LogoBadge.cpp b/Modules/Graphics/Extensions/Sources/Methane/Graphics/LogoBadge.cpp index b8564acac..8d58c738d 100644 --- a/Modules/Graphics/Extensions/Sources/Methane/Graphics/LogoBadge.cpp +++ b/Modules/Graphics/Extensions/Sources/Methane/Graphics/LogoBadge.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ Logo badge rendering primitive. #include #include -#include +#include #include @@ -40,7 +40,7 @@ static LogoBadge::Settings ScaleBadgeSize(LogoBadge::Settings settings, float sc return settings; } -LogoBadge::LogoBadge(Context& context, Settings settings) +LogoBadge::LogoBadge(RenderContext& context, Settings settings) : LogoBadge(context, ImageLoader(Data::TextureProvider::Get()).LoadImageToTexture2D(context, "Logo/MethaneLogoNameWatermark.png", true), ScaleBadgeSize(settings, context.GetContentScalingFactor())) @@ -48,7 +48,7 @@ LogoBadge::LogoBadge(Context& context, Settings settings) ITT_FUNCTION_TASK(); } -LogoBadge::LogoBadge(Context& context, Texture::Ptr sp_texture, Settings settings) +LogoBadge::LogoBadge(RenderContext& context, Ptr sp_texture, Settings settings) : ScreenQuad(context, std::move(sp_texture), ScreenQuad::Settings { diff --git a/Modules/Graphics/Extensions/Sources/Methane/Graphics/ScreenQuad.cpp b/Modules/Graphics/Extensions/Sources/Methane/Graphics/ScreenQuad.cpp index b92892812..5476d786f 100644 --- a/Modules/Graphics/Extensions/Sources/Methane/Graphics/ScreenQuad.cpp +++ b/Modules/Graphics/Extensions/Sources/Methane/Graphics/ScreenQuad.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,10 +23,10 @@ Screen Quad rendering primitive. #include -#include +#include #include #include -#include +#include namespace Methane::Graphics { @@ -41,14 +41,13 @@ struct ScreenQuadVertex Mesh::Position position; Mesh::TexCoord texcoord; - using FieldsArray = std::array; - static constexpr const FieldsArray layout = { + inline static const Mesh::VertexLayout layout = { Mesh::VertexField::Position, Mesh::VertexField::TexCoord, }; }; -ScreenQuad::ScreenQuad(Context& context, Texture::Ptr sp_texture, Settings settings) +ScreenQuad::ScreenQuad(RenderContext& context, Ptr sp_texture, Settings settings) : m_settings(std::move(settings)) , m_debug_region_name(m_settings.name + " Screen-Quad rendering") , m_sp_texture(std::move(sp_texture)) @@ -58,23 +57,39 @@ ScreenQuad::ScreenQuad(Context& context, Texture::Ptr sp_texture, Settings setti if (!m_sp_texture) throw std::invalid_argument("Screen-quad texture can not be empty."); - const Context::Settings& context_settings = context.GetSettings(); + QuadMesh quad_mesh(ScreenQuadVertex::layout, 2.f, 2.f); + + const RenderContext::Settings& context_settings = context.GetSettings(); RenderState::Settings state_settings; - state_settings.sp_program = Program::Create(context, { + state_settings.sp_program = Program::Create(context, + Program::Settings { - Shader::CreateVertex(context, { Data::ShaderProvider::Get(), { "ScreenQuad", "ScreenQuadVS" }, { } }), - Shader::CreatePixel( context, { Data::ShaderProvider::Get(), { "ScreenQuad", "ScreenQuadPS" }, { } }), - }, - { { { - { "input_position", "POSITION" }, - { "input_texcoord", "TEXCOORD" }, - } } }, - { "g_constants", "g_texture", "g_sampler" }, - { }, - { context_settings.color_format }, - context_settings.depth_stencil_format - }); + Program::Shaders + { + Shader::CreateVertex(context, { Data::ShaderProvider::Get(), { "ScreenQuad", "ScreenQuadVS" }, { } }), + Shader::CreatePixel( context, { Data::ShaderProvider::Get(), { "ScreenQuad", "ScreenQuadPS" }, { } }), + }, + Program::InputBufferLayouts + { + Program::InputBufferLayout + { + Program::InputBufferLayout::ArgumentSemantics { quad_mesh.GetVertexLayout().GetSemantics() } + } + }, + Program::ArgumentDescriptions + { + { { Shader::Type::Pixel, "g_constants" }, Program::Argument::Modifiers::Constant }, + { { Shader::Type::Pixel, "g_texture" }, Program::Argument::Modifiers::Constant }, + { { Shader::Type::Pixel, "g_sampler" }, Program::Argument::Modifiers::Constant }, + }, + PixelFormats + { + context_settings.color_format + }, + context_settings.depth_stencil_format + } + ); state_settings.sp_program->SetName(m_settings.name + " Screen-Quad Shading"); state_settings.viewports = { GetFrameViewport(settings.screen_rect) }; state_settings.scissor_rects = { GetFrameScissorRect(settings.screen_rect) }; @@ -97,8 +112,6 @@ ScreenQuad::ScreenQuad(Context& context, Texture::Ptr sp_texture, Settings setti m_sp_texture_sampler->SetName(m_settings.name + " Screen-Quad Texture Sampler"); m_sp_texture->SetName(m_settings.name + " Screen-Quad Texture"); - RectMesh quad_mesh(Mesh::VertexLayoutFromArray(ScreenQuadVertex::layout), 2.f, 2.f); - m_sp_vertex_buffer = Buffer::CreateVertexBuffer(context, static_cast(quad_mesh.GetVertexDataSize()), static_cast(quad_mesh.GetVertexSize())); m_sp_vertex_buffer->SetName(m_settings.name + " Screen-Quad Vertex Buffer"); @@ -123,7 +136,7 @@ ScreenQuad::ScreenQuad(Context& context, Texture::Ptr sp_texture, Settings setti m_sp_const_buffer = Buffer::CreateConstantBuffer(context, Buffer::GetAlignedBufferSize(const_buffer_size)); m_sp_const_buffer->SetName(m_settings.name + " Screen-Quad Constants Buffer"); - m_sp_const_resource_bindings = Program::ResourceBindings::Create(state_settings.sp_program, { + m_sp_const_program_bindings = ProgramBindings::Create(state_settings.sp_program, { { { Shader::Type::Pixel, "g_constants" }, { { m_sp_const_buffer } } }, { { Shader::Type::Pixel, "g_texture" }, { { m_sp_texture } } }, { { Shader::Type::Pixel, "g_sampler" }, { { m_sp_texture_sampler } } }, @@ -176,7 +189,7 @@ void ScreenQuad::Draw(RenderCommandList& cmd_list) const ITT_FUNCTION_TASK(); cmd_list.Reset(m_sp_state, m_debug_region_name); - cmd_list.SetResourceBindings(*m_sp_const_resource_bindings); + cmd_list.SetProgramBindings(*m_sp_const_program_bindings); cmd_list.SetVertexBuffers({ *m_sp_vertex_buffer }); cmd_list.DrawIndexed(RenderCommandList::Primitive::Triangle, *m_sp_index_buffer); } diff --git a/Modules/Graphics/Extensions/Sources/Methane/Graphics/SkyBox.cpp b/Modules/Graphics/Extensions/Sources/Methane/Graphics/SkyBox.cpp index 6017eb244..227989d6f 100644 --- a/Modules/Graphics/Extensions/Sources/Methane/Graphics/SkyBox.cpp +++ b/Modules/Graphics/Extensions/Sources/Methane/Graphics/SkyBox.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,49 +22,60 @@ SkyBox rendering primitive ******************************************************************************/ #include -#include +#include #include #include -#include +#include namespace Methane::Graphics { -struct SkyBoxVertex +SkyBox::SkyBox(RenderContext& context, ImageLoader& image_loader, const Settings& settings) + : SkyBox(context, image_loader, settings, SphereMesh(Vertex::layout)) { - Mesh::Position position; - - using FieldsArray = std::array; - static constexpr const FieldsArray layout = { - Mesh::VertexField::Position, - }; -}; + ITT_FUNCTION_TASK(); +} -SkyBox::SkyBox(Context& context, ImageLoader& image_loader, const Settings& settings) +SkyBox::SkyBox(RenderContext& context, ImageLoader& image_loader, const Settings& settings, BaseMesh mesh) : m_settings(settings) , m_context(context) - , m_mesh_buffers(context, SphereMesh(Mesh::VertexLayoutFromArray(SkyBoxVertex::layout)), "Sky-Box") + , m_mesh_buffers(context, mesh, "Sky-Box") { ITT_FUNCTION_TASK(); m_mesh_buffers.SetTexture(image_loader.LoadImagesToTextureCube(m_context, m_settings.face_resources, m_settings.mipmapped)); - const Context::Settings& context_settings = context.GetSettings(); + const RenderContext::Settings& context_settings = context.GetSettings(); RenderState::Settings state_settings; - state_settings.sp_program = Program::Create(context, { + state_settings.sp_program = Program::Create(context, + Program::Settings { - Shader::CreateVertex(context, { Data::ShaderProvider::Get(), { "SkyBox", "SkyboxVS" }, { } }), - Shader::CreatePixel( context, { Data::ShaderProvider::Get(), { "SkyBox", "SkyboxPS" }, { } }), - }, - { { { - { "input_position", "POSITION" }, - } } }, - { "g_skybox_texture", "g_texture_sampler" }, - { }, - { context_settings.color_format }, - context_settings.depth_stencil_format - }); + Program::Shaders + { + Shader::CreateVertex(context, { Data::ShaderProvider::Get(), { "SkyBox", "SkyboxVS" }, { } }), + Shader::CreatePixel( context, { Data::ShaderProvider::Get(), { "SkyBox", "SkyboxPS" }, { } }), + }, + Program::InputBufferLayouts + { + Program::InputBufferLayout + { + Program::InputBufferLayout::ArgumentSemantics { mesh.GetVertexLayout().GetSemantics() } + } + }, + Program::ArgumentDescriptions + { + { { Shader::Type::Vertex, "g_skybox_uniforms" }, Program::Argument::Modifiers::None }, + { { Shader::Type::Pixel, "g_skybox_texture" }, Program::Argument::Modifiers::Constant }, + { { Shader::Type::Pixel, "g_texture_sampler" }, Program::Argument::Modifiers::Constant }, + }, + PixelFormats + { + context_settings.color_format + }, + context_settings.depth_stencil_format + } + ); state_settings.sp_program->SetName("Sky-box shading"); state_settings.viewports = { GetFrameViewport(context_settings.frame_size) }; state_settings.scissor_rects = { GetFrameScissorRect(context_settings.frame_size) }; @@ -84,15 +95,15 @@ SkyBox::SkyBox(Context& context, ImageLoader& image_loader, const Settings& sett m_sp_texture_sampler->SetName("Sky-box Texture Sampler"); } -Program::ResourceBindings::Ptr SkyBox::CreateResourceBindings(const Buffer::Ptr& sp_uniforms_buffer) +Ptr SkyBox::CreateProgramBindings(const Ptr& sp_uniforms_buffer) { ITT_FUNCTION_TASK(); assert(!!m_sp_state); assert(!!m_sp_state->GetSettings().sp_program); - return Program::ResourceBindings::Create(m_sp_state->GetSettings().sp_program, { + return ProgramBindings::Create(m_sp_state->GetSettings().sp_program, { { { Shader::Type::Vertex, "g_skybox_uniforms" }, { { sp_uniforms_buffer } } }, - { { Shader::Type::Pixel, "g_skybox_texture" }, { { m_mesh_buffers.GetSubsetTexturePtr() } } }, + { { Shader::Type::Pixel, "g_skybox_texture" }, { { m_mesh_buffers.GetTexturePtr() } } }, { { Shader::Type::Pixel, "g_texture_sampler" }, { { m_sp_texture_sampler } } }, }); } @@ -128,9 +139,9 @@ void SkyBox::Draw(RenderCommandList& cmd_list, MeshBufferBindings& buffer_bindin cmd_list.Reset(m_sp_state, "Sky-box rendering"); - assert(!buffer_bindings.resource_bindings_per_instance.empty()); - assert(!!buffer_bindings.resource_bindings_per_instance[0]); - m_mesh_buffers.Draw(cmd_list, *buffer_bindings.resource_bindings_per_instance[0]); + assert(!buffer_bindings.program_bindings_per_instance.empty()); + assert(!!buffer_bindings.program_bindings_per_instance[0]); + m_mesh_buffers.Draw(cmd_list, *buffer_bindings.program_bindings_per_instance[0]); } } // namespace Methane::Graphics diff --git a/Modules/Graphics/Helpers/CMakeLists.txt b/Modules/Graphics/Helpers/CMakeLists.txt index 95e07470c..67141bae1 100644 --- a/Modules/Graphics/Helpers/CMakeLists.txt +++ b/Modules/Graphics/Helpers/CMakeLists.txt @@ -10,9 +10,15 @@ set(HEADERS ${INCLUDE_DIR}/ArcBallCamera.h ${INCLUDE_DIR}/ActionCamera.h ${INCLUDE_DIR}/FpsCounter.h - ${INCLUDE_DIR}/Mesh.h ${INCLUDE_DIR}/Noise.hpp ${INCLUDE_DIR}/MathTypes.h + ${INCLUDE_DIR}/Mesh.h + ${INCLUDE_DIR}/Mesh/BaseMesh.hpp + ${INCLUDE_DIR}/Mesh/QuadMesh.hpp + ${INCLUDE_DIR}/Mesh/CubeMesh.hpp + ${INCLUDE_DIR}/Mesh/UberMesh.hpp + ${INCLUDE_DIR}/Mesh/SphereMesh.hpp + ${INCLUDE_DIR}/Mesh/IcosahedronMesh.hpp ${INCLUDE_PLATFORM_DIR}/Helpers.h ${INCLUDE_PLATFORM_DIR}/MathTypes.h ) @@ -41,7 +47,7 @@ target_link_libraries(${TARGET} MethaneDataPrimitives MethaneDataAnimation MethanePlatformUtils - MethaneDataInstrumentation + MethaneInstrumentation PerlinNoise CML ) diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/ActionCamera.h b/Modules/Graphics/Helpers/Include/Methane/Graphics/ActionCamera.h index 058f434e0..eff5f6b6d 100644 --- a/Modules/Graphics/Helpers/Include/Methane/Graphics/ActionCamera.h +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/ActionCamera.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -116,7 +116,7 @@ class ActionCamera : public ArcBallCamera static std::string GetActionName(KeyboardAction keyboard_action); protected: - using KeyboardActionAnimations = std::map; + using KeyboardActionAnimations = std::map>; void Move(const Vector3f& move_vector); void Zoom(float zoom_factor); diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/ArcBallCamera.h b/Modules/Graphics/Helpers/Include/Methane/Graphics/ArcBallCamera.h index d0b717d0b..02b3d380a 100644 --- a/Modules/Graphics/Helpers/Include/Methane/Graphics/ArcBallCamera.h +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/ArcBallCamera.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -59,7 +59,7 @@ class ArcBallCamera : public Camera Vector3f GetNormalizedSphereProjection(const Data::Point2i& mouse_screen_pos, bool is_primary) const; inline float GetRadiusInPixels(const Data::Point2f& screen_size) const noexcept - { return std::min(screen_size.x(), screen_size.y()) * m_radius_ratio / 2.f; } + { return std::min(screen_size.GetX(), screen_size.GetY()) * m_radius_ratio / 2.f; } inline const Camera& GetViewCamera() const noexcept { return m_p_view_camera ? *m_p_view_camera : *this; } diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/Camera.h b/Modules/Graphics/Helpers/Include/Methane/Graphics/Camera.h index b4bff63c5..485ae0100 100644 --- a/Modules/Graphics/Helpers/Include/Methane/Graphics/Camera.h +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/Camera.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ limitations under the License. ******************************************************************************* FILE: Methane/Graphics/Camera.h -Camera helper implementation allowing to generate view and projectrion matrices. +Camera helper implementation allowing to generate view and projection matrices. ******************************************************************************/ @@ -59,9 +59,9 @@ class Camera void Resize(float width, float height) noexcept; void SetProjection(Projection projection) noexcept { m_projection = projection; } - void ResetOrientaion() noexcept { m_current_orientation = m_default_orientation; } + void ResetOrientation() noexcept { m_current_orientation = m_default_orientation; } void SetOrientation(const Orientation& orientation) noexcept { m_current_orientation = m_default_orientation = orientation; } - void SetParamters(const Parameters& parameters) noexcept { m_parameters = parameters; } + void SetParameters(const Parameters& parameters) noexcept { m_parameters = parameters; } void RotateYaw(float deg) noexcept; void RotatePitch(float deg) noexcept; @@ -89,7 +89,7 @@ class Camera void PrintOrientation(); protected: - float GetFOVAngleY() const noexcept; + float GetFovAngleY() const noexcept; static float GetAimDistance(const Orientation& orientation) noexcept { return (orientation.aim - orientation.eye).length(); } static Vector3f GetLookDirection(const Orientation& orientation) noexcept { return orientation.aim - orientation.eye; } diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/FpsCounter.h b/Modules/Graphics/Helpers/Include/Methane/Graphics/FpsCounter.h index 17c6217b3..49e41f5be 100644 --- a/Modules/Graphics/Helpers/Include/Methane/Graphics/FpsCounter.h +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/FpsCounter.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ FPS counter calculates frame time duration with moving average window algorithm. #pragma once -#include +#include #include #include @@ -79,8 +79,8 @@ class FpsCounter const uint32_t GetFramesPerSecond() const noexcept { return static_cast(std::round(1.0 / GetAverageFrameTiming().GetTotalTimeSec())); } private: - Data::Timer m_frame_timer; - Data::Timer m_present_timer; + Timer m_frame_timer; + Timer m_present_timer; double m_present_on_gpu_wait_time_sec = 0.0; uint32_t m_averaged_timings_count = 100; FrameTiming m_frame_timings_sum; diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/Helpers.h b/Modules/Graphics/Helpers/Include/Methane/Graphics/Helpers.h index 6a3a546c3..d95db4475 100644 --- a/Modules/Graphics/Helpers/Include/Methane/Graphics/Helpers.h +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/Helpers.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/Linux/Helpers.h b/Modules/Graphics/Helpers/Include/Methane/Graphics/Linux/Helpers.h index e7e5b1680..57311d301 100644 --- a/Modules/Graphics/Helpers/Include/Methane/Graphics/Linux/Helpers.h +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/Linux/Helpers.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/Linux/MathTypes.h b/Modules/Graphics/Helpers/Include/Methane/Graphics/Linux/MathTypes.h index bc27aabe6..d43c94510 100644 --- a/Modules/Graphics/Helpers/Include/Methane/Graphics/Linux/MathTypes.h +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/Linux/MathTypes.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/MacOS/Helpers.h b/Modules/Graphics/Helpers/Include/Methane/Graphics/MacOS/Helpers.h index afe5af795..0e4b513ef 100644 --- a/Modules/Graphics/Helpers/Include/Methane/Graphics/MacOS/Helpers.h +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/MacOS/Helpers.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/MacOS/MathTypes.h b/Modules/Graphics/Helpers/Include/Methane/Graphics/MacOS/MathTypes.h index 7b3a86d8b..3af95cad7 100644 --- a/Modules/Graphics/Helpers/Include/Methane/Graphics/MacOS/MathTypes.h +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/MacOS/MathTypes.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/MathTypes.h b/Modules/Graphics/Helpers/Include/Methane/Graphics/MathTypes.h index b7d805207..2766aeef2 100644 --- a/Modules/Graphics/Helpers/Include/Methane/Graphics/MathTypes.h +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/MathTypes.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -38,7 +38,6 @@ Math types aliases. #endif #include -#include #include #include @@ -69,8 +68,6 @@ using Vector2f = cml::vector2f; using Vector3f = cml::vector3f; using Vector4f = cml::vector4f; -using Quaternionf = cml::quaternionf; - template inline std::string VectorToString(const cml::vector>& v) { diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh.h b/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh.h index 14d349631..da13608c6 100644 --- a/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh.h +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,24 +17,18 @@ limitations under the License. ******************************************************************************* FILE: Methane/Graphics/Mesh.h -Procedural mesh generators, including rect, box, etc. +Abstract mesh class ******************************************************************************/ #pragma once -#include "MathTypes.h" - +#include "Methane/Graphics/MathTypes.h" #include -#include #include #include #include -#include -#include - -#include namespace Methane::Graphics { @@ -75,15 +69,7 @@ class Mesh const Slice indices; const bool indices_adjusted; - Subset(Type in_mesh_type, const Slice& in_vertices, const Slice& in_indices, bool in_indices_adjusted) - : mesh_type(in_mesh_type) - , vertices(in_vertices) - , indices(in_indices) - , indices_adjusted(in_indices_adjusted) - { - ITT_FUNCTION_TASK(); - } - + Subset(Type in_mesh_type, const Slice& in_vertices, const Slice& in_indices, bool in_indices_adjusted); Subset(const Subset& other) = default; }; @@ -99,14 +85,15 @@ class Mesh Count }; - using VertexLayout = std::vector; - - template - static VertexLayout VertexLayoutFromArray(const std::array& layout_array) + class VertexLayout : public std::vector { - ITT_FUNCTION_TASK(); - return VertexLayout(layout_array.begin(), layout_array.end()); - } + public: + using std::vector::vector; + + std::vector GetSemantics() const; + + static std::string GetSemanticByVertexField(VertexField vertex_field); + }; Mesh(Type type, const VertexLayout& vertex_layout); @@ -155,716 +142,4 @@ class Mesh static const Colors g_colors; }; -template -class BaseMesh : public Mesh -{ -public: - using Vertices = std::vector; - - BaseMesh(Type type, const VertexLayout& vertex_layout) - : Mesh(type, vertex_layout) - { - ITT_FUNCTION_TASK(); - if (sizeof(VType) != m_vertex_size) - { - throw std::invalid_argument("Size of vertex structure differs from vertex size calculated by vertex layout."); - } - } - - const Vertices& GetVertices() const noexcept { return m_vertices; } - Data::Size GetVertexCount() const noexcept { return static_cast(m_vertices.size()); } - Data::Size GetVertexDataSize() const noexcept { return static_cast(m_vertices.size() * m_vertex_size); } - -protected: - template - FType& GetVertexField(VType& vertex, VertexField field) noexcept - { - ITT_FUNCTION_TASK(); - const int32_t field_offset = m_vertex_field_offsets[static_cast(field)]; - assert(field_offset >= 0); - return *reinterpret_cast(reinterpret_cast(&vertex) + field_offset); - } - - template - const FType& GetVertexField(const VType& vertex, VertexField field) noexcept - { - ITT_FUNCTION_TASK(); - const int32_t field_offset = m_vertex_field_offsets[static_cast(field)]; - assert(field_offset >= 0); - return *reinterpret_cast(reinterpret_cast(&vertex) + field_offset); - } - - using EdgeMidpoints = std::map; - Index AddEdgeMidpoint(const Edge& edge, EdgeMidpoints& edge_midpoinds) - { - ITT_FUNCTION_TASK(); - const auto edge_midpoint_it = edge_midpoinds.find(edge); - if (edge_midpoint_it != edge_midpoinds.end()) - return edge_midpoint_it->second; - - const VType& v1 = m_vertices[edge.first_index]; - const VType& v2 = m_vertices[edge.second_index]; - VType v_mid = { }; - - const Mesh::Position& v1_position = GetVertexField(v1, Mesh::VertexField::Position); - const Mesh::Position& v2_position = GetVertexField(v2, Mesh::VertexField::Position); - Mesh::Position& v_mid_position = GetVertexField(v_mid, Mesh::VertexField::Position); - v_mid_position = (v1_position + v2_position) / 2.f; - - if (Mesh::HasVertexField(Mesh::VertexField::Normal)) - { - const Mesh::Normal& v1_normal = GetVertexField(v1, Mesh::VertexField::Normal); - const Mesh::Normal& v2_normal = GetVertexField(v2, Mesh::VertexField::Normal); - Mesh::Normal& v_mid_normal = GetVertexField(v_mid, Mesh::VertexField::Normal); - v_mid_normal = cml::normalize(v1_normal + v2_normal); - } - - if (Mesh::HasVertexField(Mesh::VertexField::Color)) - { - const Mesh::Color& v1_color = GetVertexField(v1, Mesh::VertexField::Color); - const Mesh::Color& v2_color = GetVertexField(v2, Mesh::VertexField::Color); - Mesh::Color& v_mid_color = GetVertexField(v_mid, Mesh::VertexField::Color); - v_mid_color = (v1_color + v2_color) / 2.f; - } - - if (Mesh::HasVertexField(Mesh::VertexField::TexCoord)) - { - const Mesh::TexCoord& v1_texcoord = GetVertexField(v1, Mesh::VertexField::TexCoord); - const Mesh::TexCoord& v2_texcoord = GetVertexField(v2, Mesh::VertexField::TexCoord); - Mesh::TexCoord& v_mid_texcoord = GetVertexField(v_mid, Mesh::VertexField::TexCoord); - v_mid_texcoord = (v1_texcoord + v2_texcoord) / 2.f; - } - - const Mesh::Index v_mid_index = static_cast(m_vertices.size()); - edge_midpoinds.emplace(edge, v_mid_index); - m_vertices.push_back(v_mid); - return v_mid_index; - } - - void ComputeAverageNormals() - { - ITT_FUNCTION_TASK(); - if (!Mesh::HasVertexField(Mesh::VertexField::Normal)) - throw std::logic_error("Mesh should contain normals."); - - if (BaseMesh::m_indices.size() % 3 != 0) - throw std::logic_error("Mesh indices count should be a multiple of three representing triangles list."); - - for (VType& vertex : m_vertices) - { - Mesh::Normal& vertex_normal = GetVertexField(vertex, Mesh::VertexField::Normal); - vertex_normal = { 0.f, 0.f, 0.f }; - } - - const size_t triangles_count = BaseMesh::m_indices.size() / 3; - for (size_t triangle_index = 0; triangle_index < triangles_count; ++triangle_index) - { - VType& v1 = m_vertices[m_indices[triangle_index * 3]]; - VType& v2 = m_vertices[m_indices[triangle_index * 3 + 1]]; - VType& v3 = m_vertices[m_indices[triangle_index * 3 + 2]]; - - const Mesh::Position& p1 = GetVertexField(v1, Mesh::VertexField::Position); - const Mesh::Position& p2 = GetVertexField(v2, Mesh::VertexField::Position); - const Mesh::Position& p3 = GetVertexField(v3, Mesh::VertexField::Position); - - const Mesh::Position u = p2 - p1; - const Mesh::Position v = p3 - p1; - const Mesh::Normal n = cml::cross(u, v); - - // NOTE: weight average by contributing face area - Mesh::Normal& n1 = GetVertexField(v1, Mesh::VertexField::Normal); - n1 += n; - - Mesh::Normal& n2 = GetVertexField(v2, Mesh::VertexField::Normal); - n2 += n; - - Mesh::Normal& n3 = GetVertexField(v3, Mesh::VertexField::Normal); - n3 += n; - } - - for (VType& vertex : m_vertices) - { - Mesh::Normal& vertex_normal = GetVertexField(vertex, Mesh::VertexField::Normal); - vertex_normal.normalize(); - } - } - - void ValidateMeshData() - { - for(size_t index = 0; index < m_indices.size(); ++index) - { - const Index vertex_index = m_indices[index]; - if (vertex_index >= m_vertices.size()) - throw std::logic_error("Mesh index buffer value " + std::to_string(vertex_index) + - " at position " + std::to_string(index) + - " is out of vertex buffer size " + std::to_string(m_vertices.size())); - } - } - - Vertices m_vertices; -}; - -template -class UberMesh : public BaseMesh -{ -public: - using BaseMeshT = BaseMesh; - - UberMesh(const Mesh::VertexLayout& vertex_layout) - : BaseMeshT(Mesh::Type::Uber, vertex_layout) - { - ITT_FUNCTION_TASK(); - } - - void AddSubMesh(const BaseMeshT& sub_mesh, bool adjust_indices) - { - ITT_FUNCTION_TASK(); - const typename BaseMeshT::Vertices& sub_vertices = sub_mesh.GetVertices(); - const Mesh::Indices& sub_indices = sub_mesh.GetIndices(); - - m_subsets.emplace_back(sub_mesh.GetType(), - Mesh::Subset::Slice(static_cast(BaseMeshT::m_vertices.size()), static_cast(sub_vertices.size())), - Mesh::Subset::Slice(static_cast(Mesh::m_indices.size()), static_cast(sub_indices.size())), - adjust_indices); - - if (adjust_indices) - { - const Data::Size vertex_count = BaseMeshT::GetVertexCount(); - assert(vertex_count <= std::numeric_limits::max()); - - const Mesh::Index index_offset = static_cast(vertex_count); - std::transform(sub_indices.begin(), sub_indices.end(), std::back_inserter(Mesh::m_indices), - [index_offset](const Mesh::Index& index) - { - assert(static_cast(index_offset) + index <= std::numeric_limits::max()); - return index_offset + index; - }); - } - else - { - Mesh::m_indices.insert(Mesh::m_indices.end(), sub_indices.begin(), sub_indices.end()); - } - - BaseMeshT::m_vertices.insert(BaseMeshT::m_vertices.end(), sub_vertices.begin(), sub_vertices.end()); - } - - const Mesh::Subsets& GetSubsets() const { return m_subsets; } - size_t GetSubsetCount() const noexcept { return m_subsets.size(); } - const Mesh::Subset& GetSubset(size_t subset_index) const - { - ITT_FUNCTION_TASK(); - if (subset_index >= m_subsets.size()) - throw std::invalid_argument("Sub mesh index is out of bounds."); - - return m_subsets[subset_index]; - } - - std::pair GetSubsetVertices(size_t subset_index) const - { - ITT_FUNCTION_TASK(); - const Mesh::Subset& subset = GetSubset(subset_index); - return { BaseMeshT::GetVertices().data() + subset.vertices.offset, subset.vertices.count }; - } - - std::pair GetSubsetIndices(size_t subset_index) const - { - ITT_FUNCTION_TASK(); - const Mesh::Subset& subset = GetSubset(subset_index); - return { Mesh::GetIndices().data() + subset.indices.offset, subset.indices.count }; - } - -private: - Mesh::Subsets m_subsets; -}; - -template -class RectMesh : public BaseMesh -{ -public: - using BaseMeshT = BaseMesh; - - enum class FaceType - { - XY, - XZ, - YZ, - }; - - RectMesh(const Mesh::VertexLayout& vertex_layout, float width = 1.f, float height = 1.f, float depth_pos = 0.f, size_t color_index = 0, FaceType face_type = FaceType::XY, Mesh::Type type = Mesh::Type::Rect) - : BaseMeshT(type, vertex_layout) - , m_width(width) - , m_height(height) - , m_depth_pos(depth_pos) - { - ITT_FUNCTION_TASK(); - - const bool has_colors = Mesh::HasVertexField(Mesh::VertexField::Color); - const bool has_normals = Mesh::HasVertexField(Mesh::VertexField::Normal); - const bool has_texcoord = Mesh::HasVertexField(Mesh::VertexField::TexCoord); - - for (size_t face_vertex_idx = 0; face_vertex_idx < Mesh::g_face_positions_2d.size(); ++face_vertex_idx) - { - VType vertex = {}; - { - const Mesh::Position2D& pos_2d = Mesh::g_face_positions_2d[face_vertex_idx]; - Mesh::Position& vertex_position = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Position); - switch (face_type) - { - case FaceType::XY: vertex_position = Mesh::Position(pos_2d[0] * m_width, pos_2d[1] * m_height, m_depth_pos); break; - case FaceType::XZ: vertex_position = Mesh::Position(pos_2d[0] * m_width, m_depth_pos, pos_2d[1] * m_height); break; - case FaceType::YZ: vertex_position = Mesh::Position(m_depth_pos, pos_2d[1] * m_width, pos_2d[0] * m_height); break; - } - } - if (has_normals) - { - Mesh::Normal& vertex_normal = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Normal); - const float depth_norm = m_depth_pos ? m_depth_pos / std::abs(m_depth_pos) : 1.f; - switch (face_type) - { - case FaceType::XY: vertex_normal = Mesh::Normal(0.f, 0.f, depth_norm); break; - case FaceType::XZ: vertex_normal = Mesh::Normal(0.f, depth_norm, 0.f); break; - case FaceType::YZ: vertex_normal = Mesh::Normal(depth_norm, 0.f, 0.f); break; - } - } - if (has_colors) - { - Mesh::Color& vertex_color = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Color); - vertex_color = Mesh::g_colors[color_index % Mesh::g_colors.size()]; - } - if (has_texcoord) - { - Mesh::TexCoord& vertex_texcoord = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::TexCoord); - vertex_texcoord = Mesh::g_face_texcoords[face_vertex_idx]; - } - RectMesh::m_vertices.push_back(vertex); - } - - Mesh::m_indices = Mesh::g_face_indices; - if ( (g_axis_orientation == cml::AxisOrientation::left_handed && ((face_type == FaceType::XY && m_depth_pos >= 0) || ((face_type == FaceType::XZ || face_type == FaceType::YZ) && m_depth_pos < 0))) || - (g_axis_orientation == cml::AxisOrientation::right_handed && ((face_type == FaceType::XY && m_depth_pos < 0) || ((face_type == FaceType::XZ || face_type == FaceType::YZ) && m_depth_pos >= 0))) ) - { - std::reverse(Mesh::m_indices.begin(), Mesh::m_indices.end()); - } - } - - const float GetWidth() const noexcept { return m_width; } - const float GetHeight() const noexcept { return m_height; } - const float GetDepthPos() const noexcept { return m_depth_pos; } - -protected: - const float m_width; - const float m_height; - const float m_depth_pos; -}; - -template -class BoxMesh : public RectMesh -{ - using Positions = std::vector; - using BaseMeshT = BaseMesh; - using RectMeshT = RectMesh; - -public: - BoxMesh(const Mesh::VertexLayout& vertex_layout, float width = 1.f, float height = 1.f, float depth = 1.f) - : RectMeshT(vertex_layout, width, height, depth / 2.f, 0, RectMeshT::FaceType::XY, Mesh::Type::Box) - , m_depth(depth) - { - ITT_FUNCTION_TASK(); - AddFace(RectMeshT(vertex_layout, width, height, -depth / 2.f, 1, RectMeshT::FaceType::XY)); - AddFace(RectMeshT(vertex_layout, width, depth, height / 2.f, 2, RectMeshT::FaceType::XZ)); - AddFace(RectMeshT(vertex_layout, width, depth, -height / 2.f, 3, RectMeshT::FaceType::XZ)); - AddFace(RectMeshT(vertex_layout, height, depth, width / 2.f, 4, RectMeshT::FaceType::YZ)); - AddFace(RectMeshT(vertex_layout, height, depth, -width / 2.f, 5, RectMeshT::FaceType::YZ)); - } - - float GetDepth() const noexcept { return m_depth; } - -protected: - void AddFace(const RectMeshT& face_mesh) noexcept - { - ITT_FUNCTION_TASK(); - const size_t initial_vertices_count = BaseMeshT::m_vertices.size(); - - const typename BaseMeshT::Vertices& face_vertices = face_mesh.GetVertices(); - BaseMeshT::m_vertices.insert(BaseMeshT::m_vertices.end(), face_vertices.begin(), face_vertices.end()); - - const Mesh::Indices& face_indices = face_mesh.GetIndices(); - std::transform(face_indices.begin(), face_indices.end(), std::back_inserter(Mesh::m_indices), - [initial_vertices_count](const Mesh::Index& index) - { return static_cast(initial_vertices_count + index); }); - } - - const float m_depth; -}; - -template -class SphereMesh : public BaseMesh -{ -public: - using BaseMeshT = BaseMesh; - - SphereMesh(const Mesh::VertexLayout& vertex_layout, float radius = 1.f, uint32_t lat_lines_count = 10, uint32_t long_lines_count = 16) - : BaseMeshT(Mesh::Type::Sphere, vertex_layout) - , m_radius(radius) - , m_lat_lines_count(lat_lines_count) - , m_long_lines_count(long_lines_count) - { - ITT_FUNCTION_TASK(); - - if (Mesh::HasVertexField(Mesh::VertexField::Color)) - { - throw std::invalid_argument("Colored vertices are not supported for sphere mesh."); - } - if (m_lat_lines_count < 3) - { - throw std::invalid_argument("Lattitude lines count should not be less than 3."); - } - if (m_long_lines_count < 3) - { - throw std::invalid_argument("Longitude lines count should not be less than 3."); - } - - GenerateSphereVertices(); - GenerateSphereIndices(); - } - - float GetRadius() const noexcept { return m_radius; } - uint32_t GetLongLinesCount() const noexcept { return m_long_lines_count; } - uint32_t GetLatLinesCount() const noexcept { return m_lat_lines_count; } - -private: - uint32_t GetActualLongLinesCount() const noexcept { return Mesh::HasVertexField(Mesh::VertexField::TexCoord) ? m_long_lines_count + 1 : m_long_lines_count; } - uint32_t GetSphereFacesCount() const noexcept { return (Mesh::HasVertexField(Mesh::VertexField::TexCoord) ? m_lat_lines_count : m_lat_lines_count - 2) * m_long_lines_count * 2; } - - void GenerateSphereVertices() - { - ITT_FUNCTION_TASK(); - - // In case of textured sphere mesh, - // an additional ending longitude line of vertices is added (with same positions as for the first line), - // required to complete the texture projection on sphere - - const bool has_texcoord = Mesh::HasVertexField(Mesh::VertexField::TexCoord); - const bool has_normals = Mesh::HasVertexField(Mesh::VertexField::Normal); - const uint32_t actual_long_lines_count = GetActualLongLinesCount(); - const uint32_t cap_vertex_count = 2 * (has_texcoord ? actual_long_lines_count : 1); - - BaseMeshT::m_vertices.resize((m_lat_lines_count - 2) * actual_long_lines_count + cap_vertex_count, {}); - - if (!has_texcoord) - { - Mesh::Position& first_vertex_position = BaseMeshT::template GetVertexField(BaseMeshT::m_vertices.front(), Mesh::VertexField::Position); - Mesh::Position& last_vertex_position = BaseMeshT::template GetVertexField(BaseMeshT::m_vertices.back(), Mesh::VertexField::Position); - - first_vertex_position = Mesh::Position(0.f, m_radius, 0.f); - last_vertex_position = Mesh::Position(0.f, -m_radius, 0.f); - - if (has_normals) - { - Mesh::Normal& first_vertex_normal = BaseMeshT::template GetVertexField(BaseMeshT::m_vertices.front(), Mesh::VertexField::Normal); - Mesh::Normal& last_vertex_normal = BaseMeshT::template GetVertexField(BaseMeshT::m_vertices.back(), Mesh::VertexField::Normal); - - first_vertex_normal = Mesh::Normal(0.f, 1.f, 0.f); - last_vertex_normal = Mesh::Normal(0.f, -1.f, 0.f); - } - } - - const float texcoord_long_spacing = 1.f / (actual_long_lines_count - 1); - const float texcoord_lat_spacing = 1.f / (m_lat_lines_count + 1); - - Matrix33f pitch_step_matrix = { }, yaw_step_matrix = { }; - cml::matrix_rotation_world_x(pitch_step_matrix, -cml::constants::pi() / (m_lat_lines_count - 1)); - cml::matrix_rotation_world_y(yaw_step_matrix, -2.0 * cml::constants::pi() / m_long_lines_count); - - Matrix33f pitch_matrix = { }, yaw_matrix = { };; - pitch_matrix.identity(); - - if (!has_texcoord) - pitch_matrix = pitch_step_matrix; - - const uint32_t actual_lat_lines_count = has_texcoord ? m_lat_lines_count : m_lat_lines_count - 1; - const uint32_t first_lat_line_index = has_texcoord ? 0 : 1; - const uint32_t first_vertex_index = has_texcoord ? 0 : 1; - - for (uint32_t lat_line_index = first_lat_line_index; lat_line_index < actual_lat_lines_count; ++lat_line_index) - { - yaw_matrix.identity(); - - for(uint32_t long_line_index = 0; long_line_index < actual_long_lines_count; ++long_line_index) - { - const Matrix33f rotation_matrix = pitch_matrix * yaw_matrix; - const uint32_t vertex_index = (lat_line_index - first_lat_line_index) * actual_long_lines_count + long_line_index + first_vertex_index; - - VType& vertex = BaseMeshT::m_vertices[vertex_index]; - { - Mesh::Position& vertex_position = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Position); - vertex_position = Mesh::Position(0.f, m_radius, 0.f) * rotation_matrix; - } - if (has_normals) - { - Mesh::Normal& vertex_normal = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Normal); - vertex_normal = Mesh::Normal(0.f, 1.f, 0.f) * rotation_matrix; - } - if (has_texcoord) - { - Mesh::TexCoord& vertex_texcoord = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::TexCoord); - vertex_texcoord = Mesh::TexCoord(texcoord_long_spacing * long_line_index, texcoord_lat_spacing * lat_line_index); - } - - yaw_matrix = yaw_matrix * yaw_step_matrix; - } - - pitch_matrix = pitch_matrix * pitch_step_matrix; - } - } - - void GenerateSphereIndices() - { - ITT_FUNCTION_TASK(); - - const bool has_texcoord = Mesh::HasVertexField(Mesh::VertexField::TexCoord); - const uint32_t actual_long_lines_count = GetActualLongLinesCount(); - const uint32_t sphere_faces_count = GetSphereFacesCount(); - - BaseMeshT::m_indices.resize(sphere_faces_count * 3, 0); - - uint32_t index_offset = 0; - - if (!has_texcoord) - { - // Top cap triangles reuse single pole vertex - - for (Mesh::Index long_line_index = 0; long_line_index < actual_long_lines_count - 1; ++long_line_index) - { - BaseMeshT::m_indices[index_offset] = 0; - BaseMeshT::m_indices[index_offset + 1] = long_line_index + 2; - BaseMeshT::m_indices[index_offset + 2] = long_line_index + 1; - - index_offset += 3; - } - - BaseMeshT::m_indices[index_offset] = 0; - BaseMeshT::m_indices[index_offset + 1] = 1; - BaseMeshT::m_indices[index_offset + 2] = m_long_lines_count; - - index_offset += 3; - } - - const uint32_t vertices_count = static_cast(BaseMeshT::m_vertices.size()); - const uint32_t index_lat_lines_count = has_texcoord ? m_lat_lines_count - 1 : m_lat_lines_count - 3; - const uint32_t index_long_lines_count = has_texcoord ? m_long_lines_count : m_long_lines_count - 1; - const uint32_t first_vertex_index = has_texcoord ? 0 : 1; - - for (uint32_t lat_line_index = 0; lat_line_index < index_lat_lines_count; ++lat_line_index) - { - for (uint32_t long_line_index = 0; long_line_index < index_long_lines_count; ++long_line_index) - { - BaseMeshT::m_indices[index_offset] = (lat_line_index * actual_long_lines_count) + long_line_index + first_vertex_index; - BaseMeshT::m_indices[index_offset + 1] = (lat_line_index * actual_long_lines_count) + long_line_index + first_vertex_index + 1; - BaseMeshT::m_indices[index_offset + 2] = (lat_line_index + 1) * actual_long_lines_count + long_line_index + first_vertex_index; - - BaseMeshT::m_indices[index_offset + 3] = (lat_line_index + 1) * actual_long_lines_count + long_line_index + first_vertex_index; - BaseMeshT::m_indices[index_offset + 4] = (lat_line_index * actual_long_lines_count) + long_line_index + first_vertex_index + 1; - BaseMeshT::m_indices[index_offset + 5] = (lat_line_index + 1) * actual_long_lines_count + long_line_index + first_vertex_index + 1; - - index_offset += 6; - } - - if (!has_texcoord) - { - BaseMeshT::m_indices[index_offset] = (lat_line_index * actual_long_lines_count) + actual_long_lines_count; - BaseMeshT::m_indices[index_offset + 1] = (lat_line_index * actual_long_lines_count) + 1; - BaseMeshT::m_indices[index_offset + 2] = (lat_line_index + 1) * actual_long_lines_count + actual_long_lines_count; - - BaseMeshT::m_indices[index_offset + 3] = (lat_line_index + 1) * actual_long_lines_count + actual_long_lines_count; - BaseMeshT::m_indices[index_offset + 4] = (lat_line_index * actual_long_lines_count) + 1; - BaseMeshT::m_indices[index_offset + 5] = (lat_line_index + 1) * actual_long_lines_count + 1; - - index_offset += 6; - } - } - - if (!has_texcoord) - { - // Bottom cap triangles reuse single pole vertex - - for (uint32_t long_line_index = 0; long_line_index < index_long_lines_count; ++long_line_index) - { - BaseMeshT::m_indices[index_offset] = (vertices_count - 1); - BaseMeshT::m_indices[index_offset + 1] = (vertices_count - 1) - (long_line_index + 2); - BaseMeshT::m_indices[index_offset + 2] = (vertices_count - 1) - (long_line_index + 1); - - index_offset += 3; - } - - BaseMeshT::m_indices[index_offset] = (vertices_count - 1); - BaseMeshT::m_indices[index_offset + 1] = (vertices_count - 2); - BaseMeshT::m_indices[index_offset + 2] = (vertices_count - 1) - actual_long_lines_count; - } - } - - const float m_radius; - const uint32_t m_lat_lines_count; - const uint32_t m_long_lines_count; -}; - -template -class IcosahedronMesh : public BaseMesh -{ -public: - using BaseMeshT = BaseMesh; - - IcosahedronMesh(const Mesh::VertexLayout& vertex_layout, float radius = 1.f, uint32_t subdivisions_count = 0, bool spherify = false) - : BaseMeshT(Mesh::Type::Icosahedron, vertex_layout) - , m_radius(radius) - { - ITT_FUNCTION_TASK(); - - const bool has_colors = Mesh::HasVertexField(Mesh::VertexField::Color); - const bool has_normals = Mesh::HasVertexField(Mesh::VertexField::Normal); - const bool has_texcoord = Mesh::HasVertexField(Mesh::VertexField::TexCoord); - - if (has_colors) - { - throw std::invalid_argument("Colored vertices are not supported for icosahedron mesh."); - } - - const float a = (radius + std::sqrt(radius * 5.f)) / 2.f; - const float b = radius; - const std::array vertex_positions = {{ - {-b, a, 0 }, - { b, a, 0 }, - {-b, -a, 0 }, - { b, -a, 0 }, - { 0, -b, a }, - { 0, b, a }, - { 0, -b, -a }, - { 0, b, -a }, - { a, 0, -b }, - { a, 0, b }, - {-a, 0, -b }, - {-a, 0, b }, - }}; - - BaseMeshT::m_vertices.resize(vertex_positions.size()); - for(size_t vertex_index = 0; vertex_index < vertex_positions.size(); ++vertex_index) - { - VType& vertex = BaseMeshT::m_vertices[vertex_index]; - - Mesh::Position& vertex_position = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Position); - vertex_position = vertex_positions[vertex_index]; - - if (has_normals) - { - Mesh::Normal& vertex_normal = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Normal); - vertex_normal = cml::normalize(vertex_position); - } - - if (has_texcoord) - { - Mesh::TexCoord& vertex_texcoord = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::TexCoord); - const Mesh::Position vertex_direction = cml::normalize(vertex_position); - - vertex_texcoord[0] = std::atan2(vertex_direction[2], vertex_direction[0]) / (2.f * cml::constants::pi()) + 0.5f; - assert(0.f <= vertex_texcoord[0] && vertex_texcoord[0] <= 1.f); - - vertex_texcoord[1] = std::asin(vertex_direction[1]) / cml::constants::pi() + 0.5f; - assert(0.f <= vertex_texcoord[1] && vertex_texcoord[1] <= 1.f); - } - } - - BaseMeshT::m_indices = { - 5, 0, 11, - 1, 0, 5, - 7, 0, 1, - 10, 0, 7, - 11, 0, 10, - 9, 1, 5, - 4, 5, 11, - 2, 11, 10, - 6, 10, 7, - 8, 7, 1, - 4, 3, 9, - 2, 3, 4, - 6, 3, 2, - 8, 3, 6, - 9, 3, 8, - 5, 4, 9, - 11, 2, 4, - 10, 6, 2, - 7, 8, 6, - 1, 9, 8, - }; - - for(uint32_t subdivision = 0; subdivision < subdivisions_count; ++subdivision) - { - Subdivide(); - } - - if (spherify) - { - Spherify(); - } - } - - const float GetRadius() const noexcept { return m_radius; } - - void Subdivide() - { - ITT_FUNCTION_TASK(); - if (BaseMeshT::m_indices.size() % 3 != 0) - throw std::logic_error("Icosahedron indices count should be a multiple of three representing triangles list."); - - Mesh::Indices new_indices; - new_indices.reserve(BaseMeshT::m_indices.size() * 4); - BaseMeshT::m_vertices.reserve(BaseMeshT::m_vertices.size() * 2); - - typename BaseMeshT::EdgeMidpoints edge_midpoints; - - const size_t triangles_count = BaseMeshT::m_indices.size() / 3; - for (size_t triangle_index = 0; triangle_index < triangles_count; ++triangle_index) - { - const Mesh::Index vi1 = BaseMeshT::m_indices[triangle_index * 3]; - const Mesh::Index vi2 = BaseMeshT::m_indices[triangle_index * 3 + 1]; - const Mesh::Index vi3 = BaseMeshT::m_indices[triangle_index * 3 + 2]; - - const Mesh::Index vm1 = BaseMeshT::AddEdgeMidpoint(Mesh::Edge(vi1, vi2), edge_midpoints); - const Mesh::Index vm2 = BaseMeshT::AddEdgeMidpoint(Mesh::Edge(vi2, vi3), edge_midpoints); - const Mesh::Index vm3 = BaseMeshT::AddEdgeMidpoint(Mesh::Edge(vi3, vi1), edge_midpoints); - - std::array indices = { - vi1, vm1, vm3, - vm1, vi2, vm2, - vm1, vm2, vm3, - vm3, vm2, vi3, - }; - new_indices.insert(new_indices.end(), indices.begin(), indices.end()); - } - - std::swap(BaseMeshT::m_indices, new_indices); - } - - void Spherify() - { - ITT_FUNCTION_TASK(); - - const bool has_normals = Mesh::HasVertexField(Mesh::VertexField::Normal); - - for(VType& vertex : BaseMeshT::m_vertices) - { - Mesh::Position& vertex_position = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Position); - vertex_position = cml::normalize(vertex_position) * m_radius; - - if (has_normals) - { - Mesh::Normal& vertex_normal = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Normal); - vertex_normal = cml::normalize(vertex_position); - } - } - } - -protected: - const float m_radius; -}; - } // namespace Methane::Graphics diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/BaseMesh.hpp b/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/BaseMesh.hpp new file mode 100644 index 000000000..10185186b --- /dev/null +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/BaseMesh.hpp @@ -0,0 +1,184 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/BaseMesh.hpp +Base mesh implementation with customizable vertex types + +******************************************************************************/ + +#pragma once + +#include +#include + +#include +#include + +namespace Methane::Graphics +{ + +template +class BaseMesh : public Mesh +{ +public: + using Vertices = std::vector; + + BaseMesh(Type type, const VertexLayout& vertex_layout) + : Mesh(type, vertex_layout) + { + ITT_FUNCTION_TASK(); + if (sizeof(VType) != m_vertex_size) + { + throw std::invalid_argument("Size of vertex structure differs from vertex size calculated by vertex layout."); + } + } + + const Vertices& GetVertices() const noexcept { return m_vertices; } + Data::Size GetVertexCount() const noexcept { return static_cast(m_vertices.size()); } + Data::Size GetVertexDataSize() const noexcept { return static_cast(m_vertices.size() * m_vertex_size); } + +protected: + template + FType& GetVertexField(VType& vertex, VertexField field) noexcept + { + ITT_FUNCTION_TASK(); + const int32_t field_offset = m_vertex_field_offsets[static_cast(field)]; + assert(field_offset >= 0); + return *reinterpret_cast(reinterpret_cast(&vertex) + field_offset); + } + + template + const FType& GetVertexField(const VType& vertex, VertexField field) noexcept + { + ITT_FUNCTION_TASK(); + const int32_t field_offset = m_vertex_field_offsets[static_cast(field)]; + assert(field_offset >= 0); + return *reinterpret_cast(reinterpret_cast(&vertex) + field_offset); + } + + using EdgeMidpoints = std::map; + Index AddEdgeMidpoint(const Edge& edge, EdgeMidpoints& edge_midpoints) + { + ITT_FUNCTION_TASK(); + const auto edge_midpoint_it = edge_midpoints.find(edge); + if (edge_midpoint_it != edge_midpoints.end()) + return edge_midpoint_it->second; + + const VType& v1 = m_vertices[edge.first_index]; + const VType& v2 = m_vertices[edge.second_index]; + VType v_mid = { }; + + const Mesh::Position& v1_position = GetVertexField(v1, Mesh::VertexField::Position); + const Mesh::Position& v2_position = GetVertexField(v2, Mesh::VertexField::Position); + Mesh::Position& v_mid_position = GetVertexField(v_mid, Mesh::VertexField::Position); + v_mid_position = (v1_position + v2_position) / 2.f; + + if (Mesh::HasVertexField(Mesh::VertexField::Normal)) + { + const Mesh::Normal& v1_normal = GetVertexField(v1, Mesh::VertexField::Normal); + const Mesh::Normal& v2_normal = GetVertexField(v2, Mesh::VertexField::Normal); + Mesh::Normal& v_mid_normal = GetVertexField(v_mid, Mesh::VertexField::Normal); + v_mid_normal = cml::normalize(v1_normal + v2_normal); + } + + if (Mesh::HasVertexField(Mesh::VertexField::Color)) + { + const Mesh::Color& v1_color = GetVertexField(v1, Mesh::VertexField::Color); + const Mesh::Color& v2_color = GetVertexField(v2, Mesh::VertexField::Color); + Mesh::Color& v_mid_color = GetVertexField(v_mid, Mesh::VertexField::Color); + v_mid_color = (v1_color + v2_color) / 2.f; + } + + if (Mesh::HasVertexField(Mesh::VertexField::TexCoord)) + { + const Mesh::TexCoord& v1_texcoord = GetVertexField(v1, Mesh::VertexField::TexCoord); + const Mesh::TexCoord& v2_texcoord = GetVertexField(v2, Mesh::VertexField::TexCoord); + Mesh::TexCoord& v_mid_texcoord = GetVertexField(v_mid, Mesh::VertexField::TexCoord); + v_mid_texcoord = (v1_texcoord + v2_texcoord) / 2.f; + } + + const Mesh::Index v_mid_index = static_cast(m_vertices.size()); + edge_midpoints.emplace(edge, v_mid_index); + m_vertices.push_back(v_mid); + return v_mid_index; + } + + void ComputeAverageNormals() + { + ITT_FUNCTION_TASK(); + if (!Mesh::HasVertexField(Mesh::VertexField::Normal)) + throw std::logic_error("Mesh should contain normals."); + + if (BaseMesh::m_indices.size() % 3 != 0) + throw std::logic_error("Mesh indices count should be a multiple of three representing triangles list."); + + for (VType& vertex : m_vertices) + { + Mesh::Normal& vertex_normal = GetVertexField(vertex, Mesh::VertexField::Normal); + vertex_normal = { 0.f, 0.f, 0.f }; + } + + const size_t triangles_count = BaseMesh::m_indices.size() / 3; + for (size_t triangle_index = 0; triangle_index < triangles_count; ++triangle_index) + { + VType& v1 = m_vertices[m_indices[triangle_index * 3]]; + VType& v2 = m_vertices[m_indices[triangle_index * 3 + 1]]; + VType& v3 = m_vertices[m_indices[triangle_index * 3 + 2]]; + + const Mesh::Position& p1 = GetVertexField(v1, Mesh::VertexField::Position); + const Mesh::Position& p2 = GetVertexField(v2, Mesh::VertexField::Position); + const Mesh::Position& p3 = GetVertexField(v3, Mesh::VertexField::Position); + + const Mesh::Position u = p2 - p1; + const Mesh::Position v = p3 - p1; + const Mesh::Normal n = cml::cross(u, v); + + // NOTE: weight average by contributing face area + Mesh::Normal& n1 = GetVertexField(v1, Mesh::VertexField::Normal); + n1 += n; + + Mesh::Normal& n2 = GetVertexField(v2, Mesh::VertexField::Normal); + n2 += n; + + Mesh::Normal& n3 = GetVertexField(v3, Mesh::VertexField::Normal); + n3 += n; + } + + for (VType& vertex : m_vertices) + { + Mesh::Normal& vertex_normal = GetVertexField(vertex, Mesh::VertexField::Normal); + vertex_normal.normalize(); + } + } + + void ValidateMeshData() + { + for(size_t index = 0; index < m_indices.size(); ++index) + { + const Index vertex_index = m_indices[index]; + if (vertex_index >= m_vertices.size()) + throw std::logic_error("Mesh index buffer value " + std::to_string(vertex_index) + + " at position " + std::to_string(index) + + " is out of vertex buffer size " + std::to_string(m_vertices.size())); + } + } + + Vertices m_vertices; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/CubeMesh.hpp b/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/CubeMesh.hpp new file mode 100644 index 000000000..d14699d9d --- /dev/null +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/CubeMesh.hpp @@ -0,0 +1,71 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/CubeMesh.hpp +Cube mesh generator with customizable vertex type + +******************************************************************************/ + +#pragma once + +#include "QuadMesh.hpp" + +namespace Methane::Graphics +{ + +template +class CubeMesh : public QuadMesh +{ + using Positions = std::vector; + using BaseMeshT = BaseMesh; + using QuadMeshT = QuadMesh; + +public: + explicit CubeMesh(const Mesh::VertexLayout& vertex_layout, float width = 1.f, float height = 1.f, float depth = 1.f) + : QuadMeshT(vertex_layout, width, height, depth / 2.f, 0, QuadMeshT::FaceType::XY, Mesh::Type::Box) + , m_depth(depth) + { + ITT_FUNCTION_TASK(); + AddFace(QuadMeshT(vertex_layout, width, height, -depth / 2.f, 1, QuadMeshT::FaceType::XY)); + AddFace(QuadMeshT(vertex_layout, width, depth, height / 2.f, 2, QuadMeshT::FaceType::XZ)); + AddFace(QuadMeshT(vertex_layout, width, depth, -height / 2.f, 3, QuadMeshT::FaceType::XZ)); + AddFace(QuadMeshT(vertex_layout, height, depth, width / 2.f, 4, QuadMeshT::FaceType::YZ)); + AddFace(QuadMeshT(vertex_layout, height, depth, -width / 2.f, 5, QuadMeshT::FaceType::YZ)); + } + + float GetDepth() const noexcept { return m_depth; } + +protected: + void AddFace(const QuadMeshT& face_mesh) noexcept + { + ITT_FUNCTION_TASK(); + const size_t initial_vertices_count = BaseMeshT::m_vertices.size(); + + const typename BaseMeshT::Vertices& face_vertices = face_mesh.GetVertices(); + BaseMeshT::m_vertices.insert(BaseMeshT::m_vertices.end(), face_vertices.begin(), face_vertices.end()); + + const Mesh::Indices& face_indices = face_mesh.GetIndices(); + std::transform(face_indices.begin(), face_indices.end(), std::back_inserter(Mesh::m_indices), + [initial_vertices_count](const Mesh::Index& index) + { return static_cast(initial_vertices_count + index); }); + } + + const float m_depth; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/IcosahedronMesh.hpp b/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/IcosahedronMesh.hpp new file mode 100644 index 000000000..bbf26501c --- /dev/null +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/IcosahedronMesh.hpp @@ -0,0 +1,190 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/IcosahedronMesh.hpp +Icosahedron mesh generator with customizable vertex type + +******************************************************************************/ + +#pragma once + +#include "BaseMesh.hpp" + +namespace Methane::Graphics +{ + +template +class IcosahedronMesh : public BaseMesh +{ +public: + using BaseMeshT = BaseMesh; + + explicit IcosahedronMesh(const Mesh::VertexLayout& vertex_layout, float radius = 1.f, uint32_t subdivisions_count = 0, bool spherify = false) + : BaseMeshT(Mesh::Type::Icosahedron, vertex_layout) + , m_radius(radius) + { + ITT_FUNCTION_TASK(); + + const bool has_colors = Mesh::HasVertexField(Mesh::VertexField::Color); + const bool has_normals = Mesh::HasVertexField(Mesh::VertexField::Normal); + const bool has_texcoord = Mesh::HasVertexField(Mesh::VertexField::TexCoord); + + if (has_colors) + { + throw std::invalid_argument("Colored vertices are not supported for icosahedron mesh."); + } + + const float a = (radius + std::sqrt(radius * 5.f)) / 2.f; + const float b = radius; + const std::array vertex_positions = {{ + {-b, a, 0 }, + { b, a, 0 }, + {-b, -a, 0 }, + { b, -a, 0 }, + { 0, -b, a }, + { 0, b, a }, + { 0, -b, -a }, + { 0, b, -a }, + { a, 0, -b }, + { a, 0, b }, + {-a, 0, -b }, + {-a, 0, b }, + }}; + + BaseMeshT::m_vertices.resize(vertex_positions.size()); + for(size_t vertex_index = 0; vertex_index < vertex_positions.size(); ++vertex_index) + { + VType& vertex = BaseMeshT::m_vertices[vertex_index]; + + Mesh::Position& vertex_position = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Position); + vertex_position = vertex_positions[vertex_index]; + + if (has_normals) + { + Mesh::Normal& vertex_normal = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Normal); + vertex_normal = cml::normalize(vertex_position); + } + + if (has_texcoord) + { + Mesh::TexCoord& vertex_texcoord = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::TexCoord); + const Mesh::Position vertex_direction = cml::normalize(vertex_position); + + vertex_texcoord[0] = std::atan2(vertex_direction[2], vertex_direction[0]) / (2.f * cml::constants::pi()) + 0.5f; + assert(0.f <= vertex_texcoord[0] && vertex_texcoord[0] <= 1.f); + + vertex_texcoord[1] = std::asin(vertex_direction[1]) / cml::constants::pi() + 0.5f; + assert(0.f <= vertex_texcoord[1] && vertex_texcoord[1] <= 1.f); + } + } + + BaseMeshT::m_indices = { + 5, 0, 11, + 1, 0, 5, + 7, 0, 1, + 10, 0, 7, + 11, 0, 10, + 9, 1, 5, + 4, 5, 11, + 2, 11, 10, + 6, 10, 7, + 8, 7, 1, + 4, 3, 9, + 2, 3, 4, + 6, 3, 2, + 8, 3, 6, + 9, 3, 8, + 5, 4, 9, + 11, 2, 4, + 10, 6, 2, + 7, 8, 6, + 1, 9, 8, + }; + + for(uint32_t subdivision = 0; subdivision < subdivisions_count; ++subdivision) + { + Subdivide(); + } + + if (spherify) + { + Spherify(); + } + } + + const float GetRadius() const noexcept { return m_radius; } + + void Subdivide() + { + ITT_FUNCTION_TASK(); + if (BaseMeshT::m_indices.size() % 3 != 0) + throw std::logic_error("Icosahedron indices count should be a multiple of three representing triangles list."); + + Mesh::Indices new_indices; + new_indices.reserve(BaseMeshT::m_indices.size() * 4); + BaseMeshT::m_vertices.reserve(BaseMeshT::m_vertices.size() * 2); + + typename BaseMeshT::EdgeMidpoints edge_midpoints; + + const size_t triangles_count = BaseMeshT::m_indices.size() / 3; + for (size_t triangle_index = 0; triangle_index < triangles_count; ++triangle_index) + { + const Mesh::Index vi1 = BaseMeshT::m_indices[triangle_index * 3]; + const Mesh::Index vi2 = BaseMeshT::m_indices[triangle_index * 3 + 1]; + const Mesh::Index vi3 = BaseMeshT::m_indices[triangle_index * 3 + 2]; + + const Mesh::Index vm1 = BaseMeshT::AddEdgeMidpoint(Mesh::Edge(vi1, vi2), edge_midpoints); + const Mesh::Index vm2 = BaseMeshT::AddEdgeMidpoint(Mesh::Edge(vi2, vi3), edge_midpoints); + const Mesh::Index vm3 = BaseMeshT::AddEdgeMidpoint(Mesh::Edge(vi3, vi1), edge_midpoints); + + std::array indices = { + vi1, vm1, vm3, + vm1, vi2, vm2, + vm1, vm2, vm3, + vm3, vm2, vi3, + }; + new_indices.insert(new_indices.end(), indices.begin(), indices.end()); + } + + std::swap(BaseMeshT::m_indices, new_indices); + } + + void Spherify() + { + ITT_FUNCTION_TASK(); + + const bool has_normals = Mesh::HasVertexField(Mesh::VertexField::Normal); + + for(VType& vertex : BaseMeshT::m_vertices) + { + Mesh::Position& vertex_position = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Position); + vertex_position = cml::normalize(vertex_position) * m_radius; + + if (has_normals) + { + Mesh::Normal& vertex_normal = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Normal); + vertex_normal = cml::normalize(vertex_position); + } + } + } + +protected: + const float m_radius; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/QuadMesh.hpp b/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/QuadMesh.hpp new file mode 100644 index 000000000..c8062a00b --- /dev/null +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/QuadMesh.hpp @@ -0,0 +1,111 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/QuadMesh.hpp +Quad mesh generator with customizable vertex type + +******************************************************************************/ + +#pragma once + +#include "BaseMesh.hpp" + +namespace Methane::Graphics +{ + +template +class QuadMesh : public BaseMesh +{ +public: + using BaseMeshT = BaseMesh; + + enum class FaceType + { + XY, + XZ, + YZ, + }; + + explicit QuadMesh(const Mesh::VertexLayout& vertex_layout, float width = 1.f, float height = 1.f, float depth_pos = 0.f, size_t color_index = 0, FaceType face_type = FaceType::XY, Mesh::Type type = Mesh::Type::Rect) + : BaseMeshT(type, vertex_layout) + , m_width(width) + , m_height(height) + , m_depth_pos(depth_pos) + { + ITT_FUNCTION_TASK(); + + const bool has_colors = Mesh::HasVertexField(Mesh::VertexField::Color); + const bool has_normals = Mesh::HasVertexField(Mesh::VertexField::Normal); + const bool has_texcoord = Mesh::HasVertexField(Mesh::VertexField::TexCoord); + + for (size_t face_vertex_idx = 0; face_vertex_idx < Mesh::g_face_positions_2d.size(); ++face_vertex_idx) + { + VType vertex = {}; + { + const Mesh::Position2D& pos_2d = Mesh::g_face_positions_2d[face_vertex_idx]; + Mesh::Position& vertex_position = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Position); + switch (face_type) + { + case FaceType::XY: vertex_position = Mesh::Position(pos_2d[0] * m_width, pos_2d[1] * m_height, m_depth_pos); break; + case FaceType::XZ: vertex_position = Mesh::Position(pos_2d[0] * m_width, m_depth_pos, pos_2d[1] * m_height); break; + case FaceType::YZ: vertex_position = Mesh::Position(m_depth_pos, pos_2d[1] * m_width, pos_2d[0] * m_height); break; + } + } + if (has_normals) + { + Mesh::Normal& vertex_normal = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Normal); + const float depth_norm = m_depth_pos ? m_depth_pos / std::abs(m_depth_pos) : 1.f; + switch (face_type) + { + case FaceType::XY: vertex_normal = Mesh::Normal(0.f, 0.f, depth_norm); break; + case FaceType::XZ: vertex_normal = Mesh::Normal(0.f, depth_norm, 0.f); break; + case FaceType::YZ: vertex_normal = Mesh::Normal(depth_norm, 0.f, 0.f); break; + } + } + if (has_colors) + { + Mesh::Color& vertex_color = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Color); + vertex_color = Mesh::g_colors[color_index % Mesh::g_colors.size()]; + } + if (has_texcoord) + { + Mesh::TexCoord& vertex_texcoord = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::TexCoord); + vertex_texcoord = Mesh::g_face_texcoords[face_vertex_idx]; + } + QuadMesh::m_vertices.push_back(vertex); + } + + Mesh::m_indices = Mesh::g_face_indices; + if ( (g_axis_orientation == cml::AxisOrientation::left_handed && ((face_type == FaceType::XY && m_depth_pos >= 0) || ((face_type == FaceType::XZ || face_type == FaceType::YZ) && m_depth_pos < 0))) || + (g_axis_orientation == cml::AxisOrientation::right_handed && ((face_type == FaceType::XY && m_depth_pos < 0) || ((face_type == FaceType::XZ || face_type == FaceType::YZ) && m_depth_pos >= 0))) ) + { + std::reverse(Mesh::m_indices.begin(), Mesh::m_indices.end()); + } + } + + const float GetWidth() const noexcept { return m_width; } + const float GetHeight() const noexcept { return m_height; } + const float GetDepthPos() const noexcept { return m_depth_pos; } + +protected: + const float m_width; + const float m_height; + const float m_depth_pos; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/SphereMesh.hpp b/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/SphereMesh.hpp new file mode 100644 index 000000000..0dcfd4b6e --- /dev/null +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/SphereMesh.hpp @@ -0,0 +1,242 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/SphereMesh.hpp +Sphere mesh generator with customizable vertex type + +******************************************************************************/ + +#pragma once + +#include "BaseMesh.hpp" + +namespace Methane::Graphics +{ + +template +class SphereMesh : public BaseMesh +{ +public: + using BaseMeshT = BaseMesh; + + explicit SphereMesh(const Mesh::VertexLayout& vertex_layout, float radius = 1.f, uint32_t lat_lines_count = 10, uint32_t long_lines_count = 16) + : BaseMeshT(Mesh::Type::Sphere, vertex_layout) + , m_radius(radius) + , m_lat_lines_count(lat_lines_count) + , m_long_lines_count(long_lines_count) + { + ITT_FUNCTION_TASK(); + + if (Mesh::HasVertexField(Mesh::VertexField::Color)) + { + throw std::invalid_argument("Colored vertices are not supported for sphere mesh."); + } + if (m_lat_lines_count < 3) + { + throw std::invalid_argument("Latitude lines count should not be less than 3."); + } + if (m_long_lines_count < 3) + { + throw std::invalid_argument("Longitude lines count should not be less than 3."); + } + + GenerateSphereVertices(); + GenerateSphereIndices(); + } + + float GetRadius() const noexcept { return m_radius; } + uint32_t GetLongLinesCount() const noexcept { return m_long_lines_count; } + uint32_t GetLatLinesCount() const noexcept { return m_lat_lines_count; } + +private: + uint32_t GetActualLongLinesCount() const noexcept { return Mesh::HasVertexField(Mesh::VertexField::TexCoord) ? m_long_lines_count + 1 : m_long_lines_count; } + uint32_t GetSphereFacesCount() const noexcept { return (Mesh::HasVertexField(Mesh::VertexField::TexCoord) ? m_lat_lines_count : m_lat_lines_count - 2) * m_long_lines_count * 2; } + + void GenerateSphereVertices() + { + ITT_FUNCTION_TASK(); + + // In case of textured sphere mesh, + // an additional ending longitude line of vertices is added (with same positions as for the first line), + // required to complete the texture projection on sphere + + const bool has_texcoord = Mesh::HasVertexField(Mesh::VertexField::TexCoord); + const bool has_normals = Mesh::HasVertexField(Mesh::VertexField::Normal); + const uint32_t actual_long_lines_count = GetActualLongLinesCount(); + const uint32_t cap_vertex_count = 2 * (has_texcoord ? actual_long_lines_count : 1); + + BaseMeshT::m_vertices.resize((m_lat_lines_count - 2) * actual_long_lines_count + cap_vertex_count, {}); + + if (!has_texcoord) + { + Mesh::Position& first_vertex_position = BaseMeshT::template GetVertexField(BaseMeshT::m_vertices.front(), Mesh::VertexField::Position); + Mesh::Position& last_vertex_position = BaseMeshT::template GetVertexField(BaseMeshT::m_vertices.back(), Mesh::VertexField::Position); + + first_vertex_position = Mesh::Position(0.f, m_radius, 0.f); + last_vertex_position = Mesh::Position(0.f, -m_radius, 0.f); + + if (has_normals) + { + Mesh::Normal& first_vertex_normal = BaseMeshT::template GetVertexField(BaseMeshT::m_vertices.front(), Mesh::VertexField::Normal); + Mesh::Normal& last_vertex_normal = BaseMeshT::template GetVertexField(BaseMeshT::m_vertices.back(), Mesh::VertexField::Normal); + + first_vertex_normal = Mesh::Normal(0.f, 1.f, 0.f); + last_vertex_normal = Mesh::Normal(0.f, -1.f, 0.f); + } + } + + const float texcoord_long_spacing = 1.f / (actual_long_lines_count - 1); + const float texcoord_lat_spacing = 1.f / (m_lat_lines_count + 1); + + Matrix33f pitch_step_matrix = { }, yaw_step_matrix = { }; + cml::matrix_rotation_world_x(pitch_step_matrix, -cml::constants::pi() / (m_lat_lines_count - 1)); + cml::matrix_rotation_world_y(yaw_step_matrix, -2.0 * cml::constants::pi() / m_long_lines_count); + + Matrix33f pitch_matrix = { }, yaw_matrix = { };; + pitch_matrix.identity(); + + if (!has_texcoord) + pitch_matrix = pitch_step_matrix; + + const uint32_t actual_lat_lines_count = has_texcoord ? m_lat_lines_count : m_lat_lines_count - 1; + const uint32_t first_lat_line_index = has_texcoord ? 0 : 1; + const uint32_t first_vertex_index = has_texcoord ? 0 : 1; + + for (uint32_t lat_line_index = first_lat_line_index; lat_line_index < actual_lat_lines_count; ++lat_line_index) + { + yaw_matrix.identity(); + + for(uint32_t long_line_index = 0; long_line_index < actual_long_lines_count; ++long_line_index) + { + const Matrix33f rotation_matrix = pitch_matrix * yaw_matrix; + const uint32_t vertex_index = (lat_line_index - first_lat_line_index) * actual_long_lines_count + long_line_index + first_vertex_index; + + VType& vertex = BaseMeshT::m_vertices[vertex_index]; + { + Mesh::Position& vertex_position = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Position); + vertex_position = Mesh::Position(0.f, m_radius, 0.f) * rotation_matrix; + } + if (has_normals) + { + Mesh::Normal& vertex_normal = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::Normal); + vertex_normal = Mesh::Normal(0.f, 1.f, 0.f) * rotation_matrix; + } + if (has_texcoord) + { + Mesh::TexCoord& vertex_texcoord = BaseMeshT::template GetVertexField(vertex, Mesh::VertexField::TexCoord); + vertex_texcoord = Mesh::TexCoord(texcoord_long_spacing * long_line_index, texcoord_lat_spacing * lat_line_index); + } + + yaw_matrix = yaw_matrix * yaw_step_matrix; + } + + pitch_matrix = pitch_matrix * pitch_step_matrix; + } + } + + void GenerateSphereIndices() + { + ITT_FUNCTION_TASK(); + + const bool has_texcoord = Mesh::HasVertexField(Mesh::VertexField::TexCoord); + const uint32_t actual_long_lines_count = GetActualLongLinesCount(); + const uint32_t sphere_faces_count = GetSphereFacesCount(); + + BaseMeshT::m_indices.resize(sphere_faces_count * 3, 0); + + uint32_t index_offset = 0; + + if (!has_texcoord) + { + // Top cap triangles reuse single pole vertex + + for (Mesh::Index long_line_index = 0; long_line_index < actual_long_lines_count - 1; ++long_line_index) + { + BaseMeshT::m_indices[index_offset] = 0; + BaseMeshT::m_indices[index_offset + 1] = long_line_index + 2; + BaseMeshT::m_indices[index_offset + 2] = long_line_index + 1; + + index_offset += 3; + } + + BaseMeshT::m_indices[index_offset] = 0; + BaseMeshT::m_indices[index_offset + 1] = 1; + BaseMeshT::m_indices[index_offset + 2] = m_long_lines_count; + + index_offset += 3; + } + + const uint32_t vertices_count = static_cast(BaseMeshT::m_vertices.size()); + const uint32_t index_lat_lines_count = has_texcoord ? m_lat_lines_count - 1 : m_lat_lines_count - 3; + const uint32_t index_long_lines_count = has_texcoord ? m_long_lines_count : m_long_lines_count - 1; + const uint32_t first_vertex_index = has_texcoord ? 0 : 1; + + for (uint32_t lat_line_index = 0; lat_line_index < index_lat_lines_count; ++lat_line_index) + { + for (uint32_t long_line_index = 0; long_line_index < index_long_lines_count; ++long_line_index) + { + BaseMeshT::m_indices[index_offset] = (lat_line_index * actual_long_lines_count) + long_line_index + first_vertex_index; + BaseMeshT::m_indices[index_offset + 1] = (lat_line_index * actual_long_lines_count) + long_line_index + first_vertex_index + 1; + BaseMeshT::m_indices[index_offset + 2] = (lat_line_index + 1) * actual_long_lines_count + long_line_index + first_vertex_index; + + BaseMeshT::m_indices[index_offset + 3] = (lat_line_index + 1) * actual_long_lines_count + long_line_index + first_vertex_index; + BaseMeshT::m_indices[index_offset + 4] = (lat_line_index * actual_long_lines_count) + long_line_index + first_vertex_index + 1; + BaseMeshT::m_indices[index_offset + 5] = (lat_line_index + 1) * actual_long_lines_count + long_line_index + first_vertex_index + 1; + + index_offset += 6; + } + + if (!has_texcoord) + { + BaseMeshT::m_indices[index_offset] = (lat_line_index * actual_long_lines_count) + actual_long_lines_count; + BaseMeshT::m_indices[index_offset + 1] = (lat_line_index * actual_long_lines_count) + 1; + BaseMeshT::m_indices[index_offset + 2] = (lat_line_index + 1) * actual_long_lines_count + actual_long_lines_count; + + BaseMeshT::m_indices[index_offset + 3] = (lat_line_index + 1) * actual_long_lines_count + actual_long_lines_count; + BaseMeshT::m_indices[index_offset + 4] = (lat_line_index * actual_long_lines_count) + 1; + BaseMeshT::m_indices[index_offset + 5] = (lat_line_index + 1) * actual_long_lines_count + 1; + + index_offset += 6; + } + } + + if (!has_texcoord) + { + // Bottom cap triangles reuse single pole vertex + + for (uint32_t long_line_index = 0; long_line_index < index_long_lines_count; ++long_line_index) + { + BaseMeshT::m_indices[index_offset] = (vertices_count - 1); + BaseMeshT::m_indices[index_offset + 1] = (vertices_count - 1) - (long_line_index + 2); + BaseMeshT::m_indices[index_offset + 2] = (vertices_count - 1) - (long_line_index + 1); + + index_offset += 3; + } + + BaseMeshT::m_indices[index_offset] = (vertices_count - 1); + BaseMeshT::m_indices[index_offset + 1] = (vertices_count - 2); + BaseMeshT::m_indices[index_offset + 2] = (vertices_count - 1) - actual_long_lines_count; + } + } + + const float m_radius; + const uint32_t m_lat_lines_count; + const uint32_t m_long_lines_count; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/UberMesh.hpp b/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/UberMesh.hpp new file mode 100644 index 000000000..8481618eb --- /dev/null +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/Mesh/UberMesh.hpp @@ -0,0 +1,104 @@ +/****************************************************************************** + +Copyright 2019-2020 Evgeny Gorodetskiy + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +******************************************************************************* + +FILE: Methane/Graphics/UberMesh.hpp +Uber mesh generator with customizable vertex type + +******************************************************************************/ + +#pragma once + +#include "BaseMesh.hpp" + +namespace Methane::Graphics +{ + +template +class UberMesh : public BaseMesh +{ +public: + using BaseMeshT = BaseMesh; + + explicit UberMesh(const Mesh::VertexLayout& vertex_layout) + : BaseMeshT(Mesh::Type::Uber, vertex_layout) + { + ITT_FUNCTION_TASK(); + } + + void AddSubMesh(const BaseMeshT& sub_mesh, bool adjust_indices) + { + ITT_FUNCTION_TASK(); + const typename BaseMeshT::Vertices& sub_vertices = sub_mesh.GetVertices(); + const Mesh::Indices& sub_indices = sub_mesh.GetIndices(); + + m_subsets.emplace_back(sub_mesh.GetType(), + Mesh::Subset::Slice(static_cast(BaseMeshT::m_vertices.size()), static_cast(sub_vertices.size())), + Mesh::Subset::Slice(static_cast(Mesh::m_indices.size()), static_cast(sub_indices.size())), + adjust_indices); + + if (adjust_indices) + { + const Data::Size vertex_count = BaseMeshT::GetVertexCount(); + assert(vertex_count <= std::numeric_limits::max()); + + const Mesh::Index index_offset = static_cast(vertex_count); + std::transform(sub_indices.begin(), sub_indices.end(), std::back_inserter(Mesh::m_indices), + [index_offset](const Mesh::Index& index) + { + assert(static_cast(index_offset) + index <= std::numeric_limits::max()); + return index_offset + index; + }); + } + else + { + Mesh::m_indices.insert(Mesh::m_indices.end(), sub_indices.begin(), sub_indices.end()); + } + + BaseMeshT::m_vertices.insert(BaseMeshT::m_vertices.end(), sub_vertices.begin(), sub_vertices.end()); + } + + const Mesh::Subsets& GetSubsets() const { return m_subsets; } + size_t GetSubsetCount() const noexcept { return m_subsets.size(); } + const Mesh::Subset& GetSubset(size_t subset_index) const + { + ITT_FUNCTION_TASK(); + if (subset_index >= m_subsets.size()) + throw std::invalid_argument("Sub mesh index is out of bounds."); + + return m_subsets[subset_index]; + } + + std::pair GetSubsetVertices(size_t subset_index) const + { + ITT_FUNCTION_TASK(); + const Mesh::Subset& subset = GetSubset(subset_index); + return { BaseMeshT::GetVertices().data() + subset.vertices.offset, subset.vertices.count }; + } + + std::pair GetSubsetIndices(size_t subset_index) const + { + ITT_FUNCTION_TASK(); + const Mesh::Subset& subset = GetSubset(subset_index); + return { Mesh::GetIndices().data() + subset.indices.offset, subset.indices.count }; + } + +private: + Mesh::Subsets m_subsets; +}; + +} // namespace Methane::Graphics diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/Noise.hpp b/Modules/Graphics/Helpers/Include/Methane/Graphics/Noise.hpp index 747ef3de1..96e8c3151 100644 --- a/Modules/Graphics/Helpers/Include/Methane/Graphics/Noise.hpp +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/Noise.hpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,8 +16,8 @@ limitations under the License. ******************************************************************************* -FILE: Methane/Graphics/Noise.h -Multi-octave simplex noise geneator in range [0, 1] +FILE: Methane/Graphics/Noise.hpp +Multi-octave simplex noise generator in range [0, 1] ******************************************************************************/ @@ -38,7 +38,7 @@ class NoiseOctaves public: NoiseOctaves(float persistence = 0.5f) : m_weights(GetWeights(persistence)) - , m_norm_multiplier(0.5f / GetWeightsSumm(m_weights)) + , m_norm_multiplier(0.5f / GetWeightsSum(m_weights)) { } float operator()(Vector2f pos) const @@ -88,14 +88,14 @@ class NoiseOctaves return weights; } - static float GetWeightsSumm(const WeightsArray& weights) + static float GetWeightsSum(const WeightsArray& weights) { - float weights_summ = 0.f; + float weights_sum = 0.f; for(float weight : weights) { - weights_summ += weight; + weights_sum += weight; } - return weights_summ; + return weights_sum; } const WeightsArray m_weights; diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/Windows/Helpers.h b/Modules/Graphics/Helpers/Include/Methane/Graphics/Windows/Helpers.h index 86cf75050..7075257ac 100644 --- a/Modules/Graphics/Helpers/Include/Methane/Graphics/Windows/Helpers.h +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/Windows/Helpers.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -48,7 +48,7 @@ inline void ThrowIfFailed(HRESULT hr) { if (FAILED(hr)) { - std::string error_msg = "Critical runtime error has occured: "; + std::string error_msg = "Critical runtime error has occurred: "; error_msg += std::system_category().message(hr); OutputDebugStringA((error_msg + "\n").c_str()); throw std::runtime_error(error_msg); @@ -59,7 +59,7 @@ inline void ThrowIfFailed(HRESULT hr, wrl::ComPtr& error_blob) { if (FAILED(hr)) { - std::string error_msg = "Critical runtime error has occured: "; + std::string error_msg = "Critical runtime error has occurred: "; error_msg += std::system_category().message(hr); if (error_blob.Get()) { diff --git a/Modules/Graphics/Helpers/Include/Methane/Graphics/Windows/MathTypes.h b/Modules/Graphics/Helpers/Include/Methane/Graphics/Windows/MathTypes.h index 3c94509a6..3d15d30b3 100644 --- a/Modules/Graphics/Helpers/Include/Methane/Graphics/Windows/MathTypes.h +++ b/Modules/Graphics/Helpers/Include/Methane/Graphics/Windows/MathTypes.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Helpers/Sources/Methane/Graphics/ActionCamera.cpp b/Modules/Graphics/Helpers/Sources/Methane/Graphics/ActionCamera.cpp index 358b31ca5..b39b8f683 100644 --- a/Modules/Graphics/Helpers/Sources/Methane/Graphics/ActionCamera.cpp +++ b/Modules/Graphics/Helpers/Sources/Methane/Graphics/ActionCamera.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ Interactive action-camera for rotating, moving and zooming with mouse and keyboa #include #include -#include +#include #include @@ -145,7 +145,8 @@ void ActionCamera::DoKeyboardAction(KeyboardAction keyboard_action) ITT_FUNCTION_TASK(); switch(keyboard_action) { - case KeyboardAction::Reset: ResetOrientaion(); break; + case KeyboardAction::Reset: + ResetOrientation(); break; case KeyboardAction::ChangePivot: SetPivot(m_pivot == Pivot::Aim ? Pivot::Eye : Pivot::Aim); break; default: return; diff --git a/Modules/Graphics/Helpers/Sources/Methane/Graphics/ArcBallCamera.cpp b/Modules/Graphics/Helpers/Sources/Methane/Graphics/ArcBallCamera.cpp index 8d1780e7a..62187511a 100644 --- a/Modules/Graphics/Helpers/Sources/Methane/Graphics/ArcBallCamera.cpp +++ b/Modules/Graphics/Helpers/Sources/Methane/Graphics/ArcBallCamera.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ Arc-ball camera rotation with mouse handling. ******************************************************************************/ #include -#include +#include #include @@ -34,8 +34,8 @@ using namespace Methane::Data; namespace Methane::Graphics { -static inline float square(float x) { return x * x; } -static inline float unitSign(float x) { return x / std::fabs(x); } +static inline float Square(float x) { return x * x; } +static inline float UnitSign(float x) { return x / std::fabs(x); } ArcBallCamera::ArcBallCamera(Pivot pivot, cml::AxisOrientation axis_orientation) : Camera(axis_orientation) @@ -84,7 +84,7 @@ Vector3f ArcBallCamera::GetNormalizedSphereProjection(const Point2i& mouse_scree { ITT_FUNCTION_TASK(); const Point2f& screen_size = m_p_view_camera ? m_p_view_camera->GetScreenSize() : m_screen_size; - const Point2f screen_center(screen_size.x() / 2.f, screen_size.y() / 2.f); + const Point2f screen_center(screen_size.GetX() / 2.f, screen_size.GetY() / 2.f); Point2f screen_vector = static_cast(mouse_screen_pos) - screen_center; const float screen_radius = screen_vector.length(); @@ -98,10 +98,10 @@ Vector3f ArcBallCamera::GetNormalizedSphereProjection(const Point2i& mouse_scree // Reflect coordinates for natural camera movement const Point2f mirror_multipliers = m_p_view_camera ? Point2f(inside_sphere ? 1.f : -1.f, -1.f ) * - unitSign(cml::dot(GetLookDirection(m_mouse_pressed_orientation), m_p_view_camera->GetLookDirection())) + UnitSign(cml::dot(GetLookDirection(m_mouse_pressed_orientation), m_p_view_camera->GetLookDirection())) : Point2f(-1.f, 1.f); - screen_vector.setX(screen_vector.x() * mirror_multipliers.x()); - screen_vector.setY(screen_vector.y() * mirror_multipliers.y()); + screen_vector.SetX(screen_vector.GetX() * mirror_multipliers.GetX()); + screen_vector.SetY(screen_vector.GetY() * mirror_multipliers.GetY()); // Handle rotation between 90 and 180 degrees when mouse overruns one sphere radius float z_sign = 1.f; @@ -121,7 +121,7 @@ Vector3f ArcBallCamera::GetNormalizedSphereProjection(const Point2i& mouse_scree } } - return cml::normalize(Vector3f(screen_vector, inside_sphere ? z_sign * std::sqrt(square(sphere_radius) - screen_vector.length_squared()) : 0.f)); + return cml::normalize(Vector3f(screen_vector, inside_sphere ? z_sign * std::sqrt(Square(sphere_radius) - screen_vector.length_squared()) : 0.f)); } void ArcBallCamera::ApplyLookDirection(const Vector3f& look_dir) diff --git a/Modules/Graphics/Helpers/Sources/Methane/Graphics/Camera.cpp b/Modules/Graphics/Helpers/Sources/Methane/Graphics/Camera.cpp index 0dcbbaa02..62a1e683c 100644 --- a/Modules/Graphics/Helpers/Sources/Methane/Graphics/Camera.cpp +++ b/Modules/Graphics/Helpers/Sources/Methane/Graphics/Camera.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,12 +17,12 @@ limitations under the License. ******************************************************************************* FILE: Methane/Graphics/Camera.cpp -Camera helper implementation allowing to generate view and projectrion matrices. +Camera helper implementation allowing to generate view and projection matrices. ******************************************************************************/ #include -#include +#include #include @@ -40,7 +40,7 @@ Camera::Camera(cml::AxisOrientation axis_orientation) : m_axis_orientation(axis_orientation) { ITT_FUNCTION_TASK(); - ResetOrientaion(); + ResetOrientation(); } void Camera::Resize(float width, float height) noexcept @@ -86,10 +86,10 @@ void Camera::GetProjMatrix(Matrix44f& out_proj) const noexcept switch (m_projection) { case Projection::Perspective: - cml::matrix_perspective_yfov(out_proj, GetFOVAngleY(), m_aspect_ratio, m_parameters.near_depth, m_parameters.far_depth, m_axis_orientation, cml::ZClip::z_clip_zero); + cml::matrix_perspective_yfov(out_proj, GetFovAngleY(), m_aspect_ratio, m_parameters.near_depth, m_parameters.far_depth, m_axis_orientation, cml::ZClip::z_clip_zero); break; case Projection::Orthogonal: - cml::matrix_orthographic(out_proj, m_screen_size.x(), m_screen_size.y(), m_parameters.near_depth, m_parameters.far_depth, m_axis_orientation, cml::ZClip::z_clip_zero); + cml::matrix_orthographic(out_proj, m_screen_size.GetX(), m_screen_size.GetY(), m_parameters.near_depth, m_parameters.far_depth, m_axis_orientation, cml::ZClip::z_clip_zero); break; } } @@ -119,8 +119,8 @@ Matrix44f Camera::GetViewProjMatrix() const noexcept Vector2f Camera::TransformScreenToProj(const Data::Point2i& screen_pos) const noexcept { ITT_FUNCTION_TASK(); - return { 2.f * screen_pos.x() / m_screen_size.x() - 1.f, - -(2.f * screen_pos.y() / m_screen_size.y() - 1.f) }; + return { 2.f * screen_pos.GetX() / m_screen_size.GetX() - 1.f, + -(2.f * screen_pos.GetY() / m_screen_size.GetY() - 1.f) }; } Vector3f Camera::TransformScreenToView(const Data::Point2i& screen_pos) const noexcept @@ -147,7 +147,7 @@ Vector4f Camera::TransformViewToWorld(const Vector4f& view_pos, const Orientatio return GetViewMatrix(orientation) * view_pos; } -float Camera::GetFOVAngleY() const noexcept +float Camera::GetFovAngleY() const noexcept { ITT_FUNCTION_TASK(); float fov_angle_y = m_parameters.fov_deg * cml::constants::pi() / 180.0f; diff --git a/Modules/Graphics/Helpers/Sources/Methane/Graphics/FpsCounter.cpp b/Modules/Graphics/Helpers/Sources/Methane/Graphics/FpsCounter.cpp index 8375ba6ee..8e41fe363 100644 --- a/Modules/Graphics/Helpers/Sources/Methane/Graphics/FpsCounter.cpp +++ b/Modules/Graphics/Helpers/Sources/Methane/Graphics/FpsCounter.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ FPS counter calculates frame time duration with moving average window algorithm. ******************************************************************************/ #include -#include +#include namespace Methane::Graphics { diff --git a/Modules/Graphics/Helpers/Sources/Methane/Graphics/Mesh.cpp b/Modules/Graphics/Helpers/Sources/Methane/Graphics/Mesh.cpp index fcc50503b..57a136a6b 100644 --- a/Modules/Graphics/Helpers/Sources/Methane/Graphics/Mesh.cpp +++ b/Modules/Graphics/Helpers/Sources/Methane/Graphics/Mesh.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,12 +17,12 @@ limitations under the License. ******************************************************************************* FILE: Methane/Graphics/Mesh.cpp -Procedural mesh generators, including rect, box, etc. +Abstract mesh class ******************************************************************************/ #include -#include +#include #include @@ -65,6 +65,43 @@ const Mesh::Colors Mesh::g_colors = { { 0.0f, 1.0f, 1.0f, 1.0f }, }; +std::string Mesh::VertexLayout::GetSemanticByVertexField(VertexField vertex_field) +{ + ITT_FUNCTION_TASK(); + + switch(vertex_field) + { + case VertexField::Position: return "POSITION"; + case VertexField::Normal: return "NORMAL"; + case VertexField::TexCoord: return "TEXCOORD"; + case VertexField::Color: return "COLOR"; + default: assert(0); + } + + return ""; +} + +std::vector Mesh::VertexLayout::GetSemantics() const +{ + ITT_FUNCTION_TASK(); + + std::vector semantic_names; + for(VertexField vertex_field : *this) + { + semantic_names.emplace_back(GetSemanticByVertexField(vertex_field)); + } + return semantic_names; +} + +Mesh::Subset::Subset(Type in_mesh_type, const Slice& in_vertices, const Slice& in_indices, bool in_indices_adjusted) + : mesh_type(in_mesh_type) + , vertices(in_vertices) + , indices(in_indices) + , indices_adjusted(in_indices_adjusted) +{ + ITT_FUNCTION_TASK(); +} + Mesh::VertexFieldOffsets Mesh::GetVertexFieldOffsets(const VertexLayout& vertex_layout) { ITT_FUNCTION_TASK(); diff --git a/Modules/Graphics/Helpers/Test/ArcBallCameraTest.cpp b/Modules/Graphics/Helpers/Test/ArcBallCameraTest.cpp index 58d5e7b40..5ad2a5dab 100644 --- a/Modules/Graphics/Helpers/Test/ArcBallCameraTest.cpp +++ b/Modules/Graphics/Helpers/Test/ArcBallCameraTest.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ Arc-Ball camera unit tests #include #include +#include #include #include @@ -35,29 +36,31 @@ static const Point2f g_test_screen_center = g_test_screen_size / static const Camera::Orientation g_test_view_orientation = { { 0.f, 5.f, 10.f }, { 0.f, 5.f, 0.f }, { 0.f, 1.f, 0.f } }; static const Camera::Orientation g_test_dept_orientation = { { 10.f, 7.f, 0.f }, { 0.f, 7.f, 0.f }, { 0.f, 0.f, 1.f } }; static const float g_test_radius_ratio = 0.75f; -static const float g_test_radius_pixels = g_test_screen_center.y() * g_test_radius_ratio; +static const float g_test_radius_pixels = g_test_screen_center.GetY() * g_test_radius_ratio; static const Vector3f g_axis_x = { 1.f, 0.f, 0.f }; static const Vector3f g_axis_y = { 0.f, 1.f, 0.f }; static const Vector3f g_axis_z = { 0.f, 0.f, -1.f }; +static float g_vectors_equal_epsilon = 0.00001f; + +namespace Catch { -// Approximate comparison of vectors for test purposes only -static float vectors_equal_epsilon = 0.00001f; -inline bool operator==(const Vector3f& left, const Vector3f& right) +// Override vectors comparison with approximate comparison for test purposes +template<> +bool compareEqual(Vector3f const& left, Vector3f const& right) { - for(int i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) { - if (std::fabs(left[i] - right[i]) > vectors_equal_epsilon) + if (std::fabs(left[i] - right[i]) > g_vectors_equal_epsilon) return false; } return true; } -// NOTE: keep crach header include after comparison overloads to make them work on Clang -#include +} inline void SetupCamera(ArcBallCamera& camera, const Camera::Orientation& orientation) { - camera.Resize(g_test_screen_size.x(), g_test_screen_size.y()); + camera.Resize(g_test_screen_size.GetX(), g_test_screen_size.GetY()); camera.SetOrientation(orientation); camera.SetRadiusRatio(g_test_radius_ratio); CHECK(camera.GetRadiusInPixels() == g_test_radius_pixels); @@ -79,7 +82,7 @@ inline ArcBallCamera SetupDependentCamera(const ArcBallCamera& view_camera, ArcB inline void CheckOrientation(const Camera::Orientation& actual_orientation, const Camera::Orientation& reference_orientation, float epsilon = 0.00001f) { - vectors_equal_epsilon = epsilon; + g_vectors_equal_epsilon = epsilon; CHECK(actual_orientation.aim == reference_orientation.aim); CHECK(actual_orientation.eye == reference_orientation.eye); CHECK(actual_orientation.up == reference_orientation.up); @@ -153,8 +156,8 @@ TEST_CASE("View arc-ball camera rotation around Aim pivot < 90 degrees", "[camer SECTION("Around Z-axis") { TestViewCameraRotation(test_pivot, g_test_view_orientation, - Point2i( static_cast(g_test_screen_center.x()), 0), - Point2i(0, static_cast(g_test_screen_center.y())), + Point2i(static_cast(g_test_screen_center.GetX()), 0), + Point2i(0, static_cast(g_test_screen_center.GetY())), { g_test_view_orientation.eye, g_test_view_orientation.aim, { -1.f, 0.f, 0.f } }); } } @@ -185,7 +188,7 @@ TEST_CASE("View arc-ball camera rotation around Aim pivot < 90 degrees", "[camer SECTION("Around Z axis") { TestViewCameraRotation(test_pivot, g_test_view_orientation, - Point2i(static_cast(g_test_screen_center.x()), 0), + Point2i(static_cast(g_test_screen_center.GetX()), 0), static_cast(g_test_screen_center - Point2f(g_test_radius_pixels * std::cos(test_angle_rad), g_test_radius_pixels * std::sin(test_angle_rad))), RotateOrientation(g_test_view_orientation, test_pivot, g_axis_z, test_angle_deg), test_equality_epsilon); } @@ -217,8 +220,8 @@ TEST_CASE("View arc-ball camera rotation around Aim pivot > 90 degrees", "[camer SECTION("Around Z-axis") { TestViewCameraRotation(test_pivot, g_test_view_orientation, - Point2i(static_cast(g_test_screen_center.x()), 0), - Point2i(static_cast(g_test_screen_center.x()), static_cast(g_test_screen_size.y())), + Point2i(static_cast(g_test_screen_center.GetX()), 0), + Point2i(static_cast(g_test_screen_center.GetX()), static_cast(g_test_screen_size.GetY())), { g_test_view_orientation.eye, g_test_view_orientation.aim, { 0.f, -1.f, 0.f } }); } } @@ -249,8 +252,8 @@ TEST_CASE("View arc-ball camera rotation around Aim pivot > 90 degrees", "[camer SECTION("Around Z axis") { TestViewCameraRotation(test_pivot, g_test_view_orientation, - Point2i(static_cast(g_test_screen_size.x()), static_cast(g_test_screen_center.y())), - Point2i(g_test_screen_center + Point2f(g_test_screen_center.y() * std::cos(test_angle_rad), -1.f * g_test_screen_center.y() * std::sin(test_angle_rad))), + Point2i(static_cast(g_test_screen_size.GetX()), static_cast(g_test_screen_center.GetY())), + Point2i(g_test_screen_center + Point2f(g_test_screen_center.GetY() * std::cos(test_angle_rad), -1.f * g_test_screen_center.GetY() * std::sin(test_angle_rad))), RotateOrientation(g_test_view_orientation, test_pivot, g_axis_z, test_angle_deg), test_equality_epsilon); } } @@ -281,8 +284,8 @@ TEST_CASE("View arc-ball camera rotation around Eye pivot < 90 degrees", "[camer SECTION("Around Z-axis") { TestViewCameraRotation(test_pivot, g_test_view_orientation, - Point2i(static_cast(g_test_screen_center.x()), 0), - Point2i(0, static_cast(g_test_screen_center.y())), + Point2i(static_cast(g_test_screen_center.GetX()), 0), + Point2i(0, static_cast(g_test_screen_center.GetY())), { g_test_view_orientation.eye, g_test_view_orientation.aim, { -1.f, 0.f, 0.f } }); } } @@ -313,7 +316,7 @@ TEST_CASE("View arc-ball camera rotation around Eye pivot < 90 degrees", "[camer SECTION("Around Z axis") { TestViewCameraRotation(test_pivot, g_test_view_orientation, - Point2i(static_cast(g_test_screen_center.x()), 0), + Point2i(static_cast(g_test_screen_center.GetX()), 0), static_cast(g_test_screen_center - Point2f(g_test_radius_pixels * std::cos(test_angle_rad), g_test_radius_pixels * std::sin(test_angle_rad))), RotateOrientation(g_test_view_orientation, test_pivot, g_axis_z, test_angle_deg), test_equality_epsilon); } @@ -345,8 +348,8 @@ TEST_CASE("View arc-ball camera rotation around Eye pivot > 90 degrees", "[camer SECTION("Around Z-axis") { TestViewCameraRotation(test_pivot, g_test_view_orientation, - Point2i(static_cast(g_test_screen_center.x()), 0), - Point2i(static_cast(g_test_screen_center.x()), static_cast(g_test_screen_size.y())), + Point2i(static_cast(g_test_screen_center.GetX()), 0), + Point2i(static_cast(g_test_screen_center.GetX()), static_cast(g_test_screen_size.GetY())), { g_test_view_orientation.eye, g_test_view_orientation.aim, { 0.f, -1.f, 0.f } }); } } @@ -377,8 +380,8 @@ TEST_CASE("View arc-ball camera rotation around Eye pivot > 90 degrees", "[camer SECTION("Around Z axis") { TestViewCameraRotation(test_pivot, g_test_view_orientation, - Point2i(static_cast(g_test_screen_size.x()), static_cast(g_test_screen_center.y())), - Point2i(g_test_screen_center + Point2f(g_test_screen_center.y() * std::cos(test_angle_rad), -1.f * g_test_screen_center.y() * std::sin(test_angle_rad))), + Point2i(static_cast(g_test_screen_size.GetX()), static_cast(g_test_screen_center.GetY())), + Point2i(g_test_screen_center + Point2f(g_test_screen_center.GetY() * std::cos(test_angle_rad), -1.f * g_test_screen_center.GetY() * std::sin(test_angle_rad))), RotateOrientation(g_test_view_orientation, test_pivot, g_axis_z, test_angle_deg), test_equality_epsilon); } } @@ -411,8 +414,8 @@ TEST_CASE("Dependent arc-ball camera rotation around Aim pivot < 90 degrees", "[ SECTION("Around Z-axis") { TestDependentCameraRotation(test_pivot, g_test_view_orientation, test_pivot, g_test_dept_orientation, - Point2i(static_cast(g_test_screen_center.x()), 0), - Point2i(0, static_cast(g_test_screen_center.y())), + Point2i(static_cast(g_test_screen_center.GetX()), 0), + Point2i(0, static_cast(g_test_screen_center.GetY())), { { 0.f, -3.f, 0.f }, g_test_dept_orientation.aim, g_test_dept_orientation.up }, test_equality_epsilon); } } @@ -443,7 +446,7 @@ TEST_CASE("Dependent arc-ball camera rotation around Aim pivot < 90 degrees", "[ SECTION("Around Z axis") { TestDependentCameraRotation(test_pivot, g_test_view_orientation, test_pivot, g_test_dept_orientation, - Point2i(static_cast(g_test_screen_center.x()), 0), + Point2i(static_cast(g_test_screen_center.GetX()), 0), static_cast(g_test_screen_center - Point2f(g_test_radius_pixels * std::cos(test_angle_rad), g_test_radius_pixels * std::sin(test_angle_rad))), RotateOrientation(g_test_dept_orientation, test_pivot, g_axis_z, test_angle_deg), test_equality_epsilon); } diff --git a/Modules/Graphics/Helpers/Test/Main.cpp b/Modules/Graphics/Helpers/Test/Main.cpp index 1db56dbf4..d590d1baf 100644 --- a/Modules/Graphics/Helpers/Test/Main.cpp +++ b/Modules/Graphics/Helpers/Test/Main.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Kit/CMakeLists.txt b/Modules/Graphics/Kit/CMakeLists.txt index 51209b8a4..362752478 100644 --- a/Modules/Graphics/Kit/CMakeLists.txt +++ b/Modules/Graphics/Kit/CMakeLists.txt @@ -31,6 +31,7 @@ target_link_libraries(${TARGET} ) set(PREREQUISITE_TARGETS + MethaneGraphicsCore MethaneGraphicsExtensions ) add_prerequisite_modules(${TARGET} "${PREREQUISITE_TARGETS}") diff --git a/Modules/Graphics/Kit/Include/Methane/Graphics/Kit.h b/Modules/Graphics/Kit/Include/Methane/Graphics/Kit.h index f2774f88f..0fb6b38b1 100644 --- a/Modules/Graphics/Kit/Include/Methane/Graphics/Kit.h +++ b/Modules/Graphics/Kit/Include/Methane/Graphics/Kit.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Graphics/Kit/Sources/Methane/Graphics/Kit.cpp b/Modules/Graphics/Kit/Sources/Methane/Graphics/Kit.cpp index a3205178e..429127a3e 100644 --- a/Modules/Graphics/Kit/Sources/Methane/Graphics/Kit.cpp +++ b/Modules/Graphics/Kit/Sources/Methane/Graphics/Kit.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ namespace Methane namespace Kit { -void dummy() +void Dummy() { // Prevents libtool warning for library: // the table of contents is empty (no object file members in the library define global symbols) diff --git a/Modules/Platform/App/CMakeLists.txt b/Modules/Platform/App/CMakeLists.txt index a83398285..a7a9f3b5d 100644 --- a/Modules/Platform/App/CMakeLists.txt +++ b/Modules/Platform/App/CMakeLists.txt @@ -51,9 +51,9 @@ set(LIBRARIES ${LIBRARIES} MethanePlatformUtils MethanePlatformInput MethanePlatformAppView - MethaneDataInstrumentation + MethaneInstrumentation nowide_static - cxxopts + CLI11 ) set(HEADERS ${PLATFORM_HEADERS} diff --git a/Modules/Platform/App/Include/Methane/Platform/App.h b/Modules/Platform/App/Include/Methane/Platform/App.h index 91a02ecc3..ad833a94a 100644 --- a/Modules/Platform/App/Include/Methane/Platform/App.h +++ b/Modules/Platform/App/Include/Methane/Platform/App.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Platform/App/Include/Methane/Platform/AppBase.h b/Modules/Platform/App/Include/Methane/Platform/AppBase.h index dfdcba2d0..9ddd54d5d 100644 --- a/Modules/Platform/App/Include/Methane/Platform/AppBase.h +++ b/Modules/Platform/App/Include/Methane/Platform/AppBase.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,8 +26,9 @@ Base application interface and platform-independent implementation. #include #include #include +#include -#include +#include #include #include @@ -38,7 +39,7 @@ namespace Methane::Platform struct AppEnvironment; -class AppBase +class AppBase : public CLI::App { public: struct Settings @@ -57,8 +58,6 @@ class AppBase struct Message { - using Ptr = std::unique_ptr; - enum class Type : uint32_t { Information = 0, @@ -90,28 +89,27 @@ class AppBase void UpdateAndRender(); bool HasError() const; - const Settings& GetSettings() const { return m_settings; } - const Input::State& GetInputState() const { return m_input_state; } - const Data::FrameSize& GetFrameSize() const { return m_frame_size; } - bool IsMinimized() const { return m_is_minimized; } - const cxxopts::Options& GetCmdOptions() const { return m_cmd_options; } - - // Entry point for user input handling from platform-specific implementation - Input::IActionController& InputController() { return m_input_state; } + const Settings& GetPlatformAppSettings() const { return m_settings; } + const Input::State& GetInputState() const { return m_input_state; } + const Data::FrameSize& GetFrameSize() const { return m_frame_size; } + bool IsMinimized() const { return m_is_minimized; } + Input::State& InputState() { return m_input_state; } protected: // AppBase interface virtual AppView GetView() const = 0; - virtual void ParseCommandLine(const cxxopts::ParseResult& cmd_parse_result); virtual void ShowAlert(const Message& msg); + void Deinitialize() { m_initialized = false; } + + Ptr m_sp_deferred_message; + +private: Settings m_settings; - cxxopts::Options m_cmd_options; Data::FrameRect m_window_bounds; Data::FrameSize m_frame_size; bool m_is_minimized = false; bool m_initialized = false; - Message::Ptr m_sp_deferred_message; Input::State m_input_state; }; diff --git a/Modules/Platform/App/Include/Methane/Platform/AppController.h b/Modules/Platform/App/Include/Methane/Platform/AppController.h index 0b45e0de4..5a2a4213c 100644 --- a/Modules/Platform/App/Include/Methane/Platform/AppController.h +++ b/Modules/Platform/App/Include/Methane/Platform/AppController.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,43 +29,48 @@ Base application controller providing commands like app close and help. namespace Methane::Platform { -enum class AppHelpAction : uint32_t +enum class AppAction : uint32_t { None = 0, - ShowHelp, + ShowControlsHelp, + ShowCommandLineHelp, + SwitchFullScreen, CloseApp, Count }; -class AppController final +class AppController : public Input::Controller - , public Platform::Keyboard::ActionControllerBase + , public Platform::Keyboard::ActionControllerBase { public: inline static const ActionByKeyboardState default_action_by_keyboard_state = { - { { Platform::Keyboard::Key::F1 }, AppHelpAction::ShowHelp }, - { { Platform::Keyboard::OS::key_left_ctrl, Platform::Keyboard::Key::Q }, AppHelpAction::CloseApp }, + { { Platform::Keyboard::Key::F1 }, AppAction::ShowControlsHelp }, + { { Platform::Keyboard::Key::F2 }, AppAction::ShowCommandLineHelp }, + { { Platform::Keyboard::Key::LeftControl, Platform::Keyboard::Key::F }, AppAction::SwitchFullScreen }, + { { Platform::Keyboard::OS::g_key_left_ctrl, Platform::Keyboard::Key::Q }, AppAction::CloseApp }, }; - AppController(AppBase& application, const std::string& application_help, bool show_command_line_help = false, - const ActionByKeyboardState& action_by_keyboard_state = default_action_by_keyboard_state); + AppController(AppBase& application, const std::string& application_help, + const ActionByKeyboardState& action_by_keyboard_state = default_action_by_keyboard_state); // Input::Controller implementation void OnKeyboardChanged(Platform::Keyboard::Key, Platform::Keyboard::KeyState, const Platform::Keyboard::StateChange& state_change) override; HelpLines GetHelp() const override; - void ShowHelp(); + void ShowControlsHelp(); + void ShowCommandLineHelp(); -private: +protected: // Keyboard::ActionControllerBase interface - void OnKeyboardKeyAction(AppHelpAction, Platform::Keyboard::KeyState) override { } - void OnKeyboardStateAction(AppHelpAction action) override; - std::string GetKeyboardActionName(AppHelpAction action) const override; + void OnKeyboardKeyAction(AppAction, Platform::Keyboard::KeyState) override { } + void OnKeyboardStateAction(AppAction action) override; + std::string GetKeyboardActionName(AppAction action) const override; - AppBase& m_application; - const bool m_show_command_line_help; +private: + AppBase& m_application; }; } // namespace Methane::Platform diff --git a/Modules/Platform/App/Include/Methane/Platform/Linux/AppLin.h b/Modules/Platform/App/Include/Methane/Platform/Linux/AppLin.h index 44b517783..dbff600b2 100644 --- a/Modules/Platform/App/Include/Methane/Platform/Linux/AppLin.h +++ b/Modules/Platform/App/Include/Methane/Platform/Linux/AppLin.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -47,7 +47,6 @@ class AppLin : public AppBase protected: // AppBase interface - void ParseCommandLine(const cxxopts::ParseResult& cmd_parse_result) override; void ShowAlert(const Message& msg) override; AppEnvironment m_env; diff --git a/Modules/Platform/App/Include/Methane/Platform/MacOS/AppMac.hh b/Modules/Platform/App/Include/Methane/Platform/MacOS/AppMac.hh index b3af97f11..cebd68a99 100644 --- a/Modules/Platform/App/Include/Methane/Platform/MacOS/AppMac.hh +++ b/Modules/Platform/App/Include/Methane/Platform/MacOS/AppMac.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Platform/App/Include/Methane/Platform/Windows/AppWin.h b/Modules/Platform/App/Include/Methane/Platform/Windows/AppWin.h index 58b1234a6..83c141b29 100644 --- a/Modules/Platform/App/Include/Methane/Platform/Windows/AppWin.h +++ b/Modules/Platform/App/Include/Methane/Platform/Windows/AppWin.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -49,12 +49,11 @@ class AppWin : public AppBase protected: // AppBase interface - void ParseCommandLine(const cxxopts::ParseResult& cmd_parse_result) override; void ShowAlert(const Message& msg) override; void ScheduleAlert(); - static LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + static LRESULT CALLBACK WindowProc(HWND h_wnd, UINT message, WPARAM w_param, LPARAM l_param); AppEnvironment m_env; diff --git a/Modules/Platform/App/Sources/Methane/Platform/AppBase.cpp b/Modules/Platform/App/Sources/Methane/Platform/AppBase.cpp index 136dff147..afb85c759 100644 --- a/Modules/Platform/App/Sources/Methane/Platform/AppBase.cpp +++ b/Modules/Platform/App/Sources/Methane/Platform/AppBase.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,7 +23,9 @@ Base application interface and platform-independent implementation. #include #include -#include +#include + +#include #include #include @@ -33,96 +35,49 @@ namespace Methane::Platform { AppBase::AppBase(const AppBase::Settings& settings) - : m_settings(settings) - , m_cmd_options(GetExecutableFileName(), settings.name) + : CLI::App(settings.name, GetExecutableFileName()) + , m_settings(settings) { ITT_FUNCTION_TASK(); - m_cmd_options - .allow_unrecognised_options() - .add_options() - ("help", "Print command line options help") - ("w,width", "Window width in pixels or as ratio of desctop width", cxxopts::value()) - ("h,height", "Window height in pixels or as ratio of desctop height", cxxopts::value()); -} -void AppBase::ParseCommandLine(const cxxopts::ParseResult& cmd_parse_result) -{ - ITT_FUNCTION_TASK(); - if (cmd_parse_result.count("help")) - { - const Message help_msg = { - Message::Type::Information, - "Command Line Options", - m_cmd_options.help() - }; - Alert(help_msg, true); - } - if (cmd_parse_result.count("width")) - { - m_settings.width = cmd_parse_result["width"].as(); - } - if (cmd_parse_result.count("height")) - { - m_settings.height = cmd_parse_result["height"].as(); - } + add_option("-w,--width", m_settings.width, "Window width in pixels or as ratio of desktop width", true); + add_option("-x,--height", m_settings.height, "Window height in pixels or as ratio of desktop height", true); + add_option("-f,--full-screen", m_settings.is_full_screen, "Full-screen mode", true); + +#ifdef __APPLE__ + // When application is opened on MacOS with its Bundle, + // OS adds an additional command-line option which looks like "-psn_0_23004655" which should be allowed + allow_extras(); +#endif } int AppBase::Run(const RunArgs& args) { ITT_FUNCTION_TASK(); -#ifdef __APPLE__ - // NOTE: MacOS bundle process serial number argument must be skipped because of unsupported syntax (underscores) - const std::string macos_psn_arg_prefix = "-psn_"; -#endif - - // Create a mutable copy of command line args to let the parser modify it - int mutable_args_count = 0; - std::vector mutable_arg_values(args.cmd_arg_count, nullptr); - for (int argi = 0; argi < args.cmd_arg_count; argi++) - { - const size_t arg_value_size = strlen(args.cmd_arg_values[argi]) + 1; -#ifdef __APPLE__ - if (strncmp(args.cmd_arg_values[argi], macos_psn_arg_prefix.data(), std::min(arg_value_size - 1, macos_psn_arg_prefix.length())) == 0) - continue; -#endif - mutable_arg_values[mutable_args_count] = new char[arg_value_size]; -#ifdef _WIN32 - strcpy_s(mutable_arg_values[argi], arg_value_size, args.cmd_arg_values[argi]); -#elif defined __APPLE__ - strlcpy(mutable_arg_values[argi], args.cmd_arg_values[argi], arg_value_size); -#elif defined __linux__ - strcpy(mutable_arg_values[argi], args.cmd_arg_values[argi]); -#endif - mutable_args_count++; - }; - - // Parse command line - int return_code = 0; try { - char** p_mutable_arg_values = mutable_arg_values.data(); - const cxxopts::ParseResult cmd_parse_result = m_cmd_options.parse(mutable_args_count, p_mutable_arg_values); - ParseCommandLine(cmd_parse_result); + parse(args.cmd_arg_count, args.cmd_arg_values); } - catch (const cxxopts::OptionException& e) + catch(const CLI::CallForHelp&) { - const Message help_msg = { + Alert(Message{ + Message::Type::Information, + "Command Line Options", + help() + }, true); + } + catch(const CLI::ParseError& e) + { + Alert(Message{ Message::Type::Error, "Command Line Parse Error", - std::string("Failed to parse command line option: ") + e.what() - }; - Alert(help_msg); - return_code = 1; + std::string("Failed to parse command line: ") + e.what() + }); + return exit(e); } - // Delete mutable args - for (char* p_arg_value : mutable_arg_values) - { - delete[](p_arg_value); - }; - - return return_code; + return 0; } void AppBase::Init() @@ -166,13 +121,13 @@ void AppBase::ShowAlert(const Message&) ITT_FUNCTION_TASK(); // Message box interrupts message loop so that application looses all key release events - // We asssume that user has released all previously pressed keys and simulate these events + // We assume that user has released all previously pressed keys and simulate these events m_input_state.ReleaseAllKeys(); } void AppBase::UpdateAndRender() { - // Do not render if error has occured and is being displayed in message box + // Do not render if error has occurred and is being displayed in message box if (HasError()) return; diff --git a/Modules/Platform/App/Sources/Methane/Platform/AppController.cpp b/Modules/Platform/App/Sources/Methane/Platform/AppController.cpp index 8bf64a5a9..d5f8b83c3 100644 --- a/Modules/Platform/App/Sources/Methane/Platform/AppController.cpp +++ b/Modules/Platform/App/Sources/Methane/Platform/AppController.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,7 +22,9 @@ Base application controller providing commands like app close and help. ******************************************************************************/ #include -#include +#include +#include +#include #include #include @@ -30,12 +32,10 @@ Base application controller providing commands like app close and help. namespace Methane::Platform { -AppController::AppController(AppBase& application, const std::string& application_help, bool show_command_line_help, - const ActionByKeyboardState& action_by_keyboard_state) +AppController::AppController(AppBase& application, const std::string& application_help, const ActionByKeyboardState& action_by_keyboard_state) : Controller(application_help) - , Keyboard::ActionControllerBase(action_by_keyboard_state, {}) + , Keyboard::ActionControllerBase(action_by_keyboard_state, {}) , m_application(application) - , m_show_command_line_help(show_command_line_help) { ITT_FUNCTION_TASK(); } @@ -43,29 +43,33 @@ AppController::AppController(AppBase& application, const std::string& applicatio void AppController::OnKeyboardChanged(Keyboard::Key key, Platform::Keyboard::KeyState key_state, const Keyboard::StateChange& state_change) { ITT_FUNCTION_TASK(); - Keyboard::ActionControllerBase::OnKeyboardChanged(key, key_state, state_change); + Keyboard::ActionControllerBase::OnKeyboardChanged(key, key_state, state_change); } -void AppController::OnKeyboardStateAction(AppHelpAction action) +void AppController::OnKeyboardStateAction(AppAction action) { ITT_FUNCTION_TASK(); switch(action) { - case AppHelpAction::ShowHelp: ShowHelp(); break; - case AppHelpAction::CloseApp: m_application.Close(); break; - default: assert(0); + case AppAction::ShowControlsHelp: ShowControlsHelp(); break; + case AppAction::ShowCommandLineHelp: ShowCommandLineHelp(); break; + case AppAction::SwitchFullScreen: m_application.SetFullScreen(!m_application.GetPlatformAppSettings().is_full_screen); break; + case AppAction::CloseApp: m_application.Close(); break; + default: assert(0); } } -std::string AppController::GetKeyboardActionName(AppHelpAction action) const +std::string AppController::GetKeyboardActionName(AppAction action) const { ITT_FUNCTION_TASK(); switch (action) { - case AppHelpAction::None: return "none"; - case AppHelpAction::ShowHelp: return "show application help"; - case AppHelpAction::CloseApp: return "close application"; - default: assert(0); return ""; + case AppAction::None: return "none"; + case AppAction::ShowControlsHelp: return "show application controls help"; + case AppAction::ShowCommandLineHelp: return "show application command-line help"; + case AppAction::SwitchFullScreen: return "switch full-screen mode"; + case AppAction::CloseApp: return "close the application"; + default: assert(0); return ""; } } @@ -75,13 +79,13 @@ Input::IHelpProvider::HelpLines AppController::GetHelp() const return GetKeyboardHelp(); } -void AppController::ShowHelp() +void AppController::ShowControlsHelp() { ITT_FUNCTION_TASK(); std::stringstream help_stream; std::string single_offset = " "; bool is_first_controller = true; - for (const Controller::Ptr& sp_controller : m_application.GetInputState().GetControllers()) + for (const Ptr& sp_controller : m_application.GetInputState().GetControllers()) { assert(!!sp_controller); if (!sp_controller) continue; @@ -131,32 +135,32 @@ void AppController::ShowHelp() first_line = false; } } - - if (m_show_command_line_help) - { - const std::string cmd_line_help = m_application.GetCmdOptions().help(); - if (!cmd_line_help.empty()) - { - if (!is_first_controller) - { - help_stream << std::endl; - } - help_stream << "COMMAND LINE OPTIONS" << std::endl; - help_stream << std::endl << cmd_line_help; - } - } if (!is_first_controller) { help_stream << std::endl; } - help_stream << std::endl << "Powered by Methane Kit: https://github.com/egorodet/MethaneKit"; - + help_stream << std::endl << "Powered by Methane Kit v" METHANE_VERSION_STR + << std::endl << "https://github.com/egorodet/MethaneKit"; + m_application.Alert({ AppBase::Message::Type::Information, - "Application Help", + "Application Controls Help", help_stream.str() }); } +void AppController::ShowCommandLineHelp() +{ + ITT_FUNCTION_TASK(); + std::stringstream help_stream; + + const std::string cmd_line_help = m_application.help(); + m_application.Alert({ + AppBase::Message::Type::Information, + "Application Command-Line Help", + cmd_line_help + }); +} + } // namespace Methane::Platform diff --git a/Modules/Platform/App/Sources/Methane/Platform/Linux/AppLin.cpp b/Modules/Platform/App/Sources/Methane/Platform/Linux/AppLin.cpp index 17b6c263b..d76eba92e 100644 --- a/Modules/Platform/App/Sources/Methane/Platform/Linux/AppLin.cpp +++ b/Modules/Platform/App/Sources/Methane/Platform/Linux/AppLin.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ Linux application implementation. #include #include -#include +#include namespace Methane::Platform { @@ -34,12 +34,6 @@ AppLin::AppLin(const AppBase::Settings& settings) ITT_FUNCTION_TASK(); } -void AppLin::ParseCommandLine(const cxxopts::ParseResult& cmd_parse_result) -{ - ITT_FUNCTION_TASK(); - AppBase::ParseCommandLine(cmd_parse_result); -} - int AppLin::Run(const RunArgs& args) { return 0; diff --git a/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppDelegate.hh b/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppDelegate.hh index 2aeb9e603..508f213e6 100644 --- a/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppDelegate.hh +++ b/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppDelegate.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -34,7 +34,7 @@ namespace Methane { namespace Platform { class AppMac; } } @property (nonatomic, strong, nonnull) IBOutlet AppViewController* viewController; @property (nonatomic, readonly, nullable) NSWindow* window; -- (id _Nullable) initWithApp : (Methane::Platform::AppMac* _Nonnull) p_app andSettings : (Methane::Platform::AppBase::Settings* _Nonnull) p_settings; +- (id _Nullable) initWithApp : (Methane::Platform::AppMac* _Nonnull) p_app andSettings : (const Methane::Platform::AppBase::Settings* _Nonnull) p_settings; - (void) run; - (void) alert : (nonnull NSString*) ns_title withInformation: (nonnull NSString*) ns_info andStyle: (NSAlertStyle) ns_alert_style; diff --git a/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppDelegate.mm b/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppDelegate.mm index 204898e7f..da881e797 100644 --- a/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppDelegate.mm +++ b/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppDelegate.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ #include #include -#include +#include #include @@ -37,7 +37,7 @@ @implementation AppDelegate @synthesize window = _window; -- (id) initWithApp : (AppMac*) p_app andSettings : (AppBase::Settings*) p_settings +- (id) initWithApp : (AppMac*) p_app andSettings : (const AppBase::Settings*) p_settings { ITT_FUNCTION_TASK(); @@ -45,26 +45,26 @@ - (id) initWithApp : (AppMac*) p_app andSettings : (AppBase::Settings*) p_settin if (!self || !p_settings) return nil; - NSScreen* mainScreen = [NSScreen mainScreen]; - CGFloat frame_width = p_settings->width < 1.0 ? mainScreen.frame.size.width * (p_settings->width > 0.0 ? p_settings->width : 0.7) + NSScreen* ns_main_screen = [NSScreen mainScreen]; + CGFloat frame_width = p_settings->width < 1.0 ? ns_main_screen.frame.size.width * (p_settings->width > 0.0 ? p_settings->width : 0.7) : static_cast(p_settings->width); - CGFloat frame_height = p_settings->height < 1.0 ? mainScreen.frame.size.height * (p_settings->height > 0.0 ? p_settings->height : 0.7) + CGFloat frame_height = p_settings->height < 1.0 ? ns_main_screen.frame.size.height * (p_settings->height > 0.0 ? p_settings->height : 0.7) : static_cast(p_settings->height); NSRect frame = NSMakeRect(0, 0, frame_width, frame_height); - NSUInteger styleMask = NSWindowStyleMaskTitled | + NSUInteger style_mask = NSWindowStyleMaskTitled | NSWindowStyleMaskResizable | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; NSBackingStoreType backing = NSBackingStoreBuffered; - _window = [[NSWindow alloc] initWithContentRect:frame styleMask:styleMask backing:backing defer:YES]; - _window.title = MacOS::ConvertToNSType(p_settings->name); + _window = [[NSWindow alloc] initWithContentRect:frame styleMask:style_mask backing:backing defer:YES]; + _window.title = MacOS::ConvertToNsType(p_settings->name); _window.delegate = [[WindowDelegate alloc] initWithApp:p_app]; [_window center]; - NSRect backing_frame = [mainScreen convertRectToBacking:frame]; + NSRect backing_frame = [ns_main_screen convertRectToBacking:frame]; self.viewController = [[AppViewController alloc] initWithApp:p_app andFrameRect:backing_frame]; p_app->SetWindow(_window); diff --git a/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppMac.mm b/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppMac.mm index 8c39cfc5e..2302d85a6 100644 --- a/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppMac.mm +++ b/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppMac.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,12 +23,12 @@ #include #include -#include +#include using namespace Methane::Platform; using namespace Methane::MacOS; -NSAlertStyle ConvertMessageTypeToNSAlertStyle(AppBase::Message::Type msg_type) +NSAlertStyle ConvertMessageTypeToNsAlertStyle(AppBase::Message::Type msg_type) { ITT_FUNCTION_TASK(); switch(msg_type) @@ -42,7 +42,7 @@ NSAlertStyle ConvertMessageTypeToNSAlertStyle(AppBase::Message::Type msg_type) AppMac::AppMac(const AppBase::Settings& settings) : AppBase(settings) , m_ns_app([NSApplication sharedApplication]) - , m_ns_app_delegate([[AppDelegate alloc] initWithApp:this andSettings: &m_settings]) + , m_ns_app_delegate([[AppDelegate alloc] initWithApp:this andSettings: &settings]) { ITT_FUNCTION_TASK(); [m_ns_app setDelegate: m_ns_app_delegate]; @@ -108,7 +108,7 @@ NSAlertStyle ConvertMessageTypeToNSAlertStyle(AppBase::Message::Type msg_type) void AppMac::SetWindowTitle(const std::string& title_text) { ITT_FUNCTION_TASK(); - NSString* ns_title_text = ConvertToNSType(title_text); + NSString* ns_title_text = ConvertToNsType(title_text); dispatch_async(dispatch_get_main_queue(), ^(void){ m_ns_window.title = ns_title_text; }); @@ -124,9 +124,9 @@ NSAlertStyle ConvertMessageTypeToNSAlertStyle(AppBase::Message::Type msg_type) { ITT_FUNCTION_TASK(); assert(m_ns_app_delegate); - [m_ns_app_delegate alert: ConvertToNSType(msg.title) - withInformation: ConvertToNSType(msg.information) - andStyle: ConvertMessageTypeToNSAlertStyle(msg.type)]; + [m_ns_app_delegate alert: ConvertToNsType(msg.title) + withInformation: ConvertToNsType(msg.information) + andStyle: ConvertMessageTypeToNsAlertStyle(msg.type)]; AppBase::ShowAlert(msg); } diff --git a/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppViewController.hh b/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppViewController.hh index 456a2ac3f..0cb02125e 100644 --- a/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppViewController.hh +++ b/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppViewController.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppViewController.mm b/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppViewController.mm index b3c3845f8..09c30458b 100644 --- a/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppViewController.mm +++ b/Modules/Platform/App/Sources/Methane/Platform/MacOS/AppViewController.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ #include #include -#include +#include #include @@ -114,7 +114,7 @@ - (void) keyDown:(NSEvent *)event ITT_FUNCTION_TASK(); assert(!!m_p_app); - m_p_app->InputController().OnKeyboardChanged(Keyboard::KeyConverter({ [event keyCode], [event modifierFlags] }).GetKey(), Keyboard::KeyState::Pressed); + m_p_app->InputState().OnKeyboardChanged(Keyboard::KeyConverter({ [event keyCode], [event modifierFlags] }).GetKey(), Keyboard::KeyState::Pressed); } - (void) keyUp:(NSEvent *)event @@ -122,7 +122,7 @@ - (void) keyUp:(NSEvent *)event ITT_FUNCTION_TASK(); assert(!!m_p_app); - m_p_app->InputController().OnKeyboardChanged(Keyboard::KeyConverter({ [event keyCode], [event modifierFlags] }).GetKey(), Keyboard::KeyState::Released); + m_p_app->InputState().OnKeyboardChanged(Keyboard::KeyConverter({ [event keyCode], [event modifierFlags] }).GetKey(), Keyboard::KeyState::Released); } - (void) flagsChanged:(NSEvent *)event @@ -130,7 +130,7 @@ - (void) flagsChanged:(NSEvent *)event ITT_FUNCTION_TASK(); assert(!!m_p_app); - m_p_app->InputController().OnModifiersChanged(Keyboard::KeyConverter({ [event keyCode], [event modifierFlags] }).GetModifiers()); + m_p_app->InputState().OnModifiersChanged(Keyboard::KeyConverter({ [event keyCode], [event modifierFlags] }).GetModifiers()); } // ====== Mouse event handlers ====== @@ -143,7 +143,7 @@ - (void)mouseMoved:(NSEvent *)event NSPoint pos = [event locationInWindow]; pos.x *= self.view.window.backingScaleFactor; pos.y = (m_frame_rect.size.height - pos.y) * self.view.window.backingScaleFactor; - m_p_app->InputController().OnMousePositionChanged({ static_cast(pos.x), static_cast(pos.y) }); + m_p_app->InputState().OnMousePositionChanged({ static_cast(pos.x), static_cast(pos.y) }); } - (void)mouseDown:(NSEvent *)event @@ -151,7 +151,7 @@ - (void)mouseDown:(NSEvent *)event ITT_FUNCTION_TASK(); assert(!!m_p_app); - m_p_app->InputController().OnMouseButtonChanged(Mouse::Button::Left, Mouse::ButtonState::Pressed); + m_p_app->InputState().OnMouseButtonChanged(Mouse::Button::Left, Mouse::ButtonState::Pressed); } - (void)mouseUp:(NSEvent *)event @@ -159,7 +159,7 @@ - (void)mouseUp:(NSEvent *)event ITT_FUNCTION_TASK(); assert(!!m_p_app); - m_p_app->InputController().OnMouseButtonChanged(Mouse::Button::Left, Mouse::ButtonState::Released); + m_p_app->InputState().OnMouseButtonChanged(Mouse::Button::Left, Mouse::ButtonState::Released); } - (void)mouseDragged:(NSEvent *)event @@ -173,7 +173,7 @@ - (void)rightMouseDown:(NSEvent *)event ITT_FUNCTION_TASK(); assert(!!m_p_app); - m_p_app->InputController().OnMouseButtonChanged(Mouse::Button::Right, Mouse::ButtonState::Pressed); + m_p_app->InputState().OnMouseButtonChanged(Mouse::Button::Right, Mouse::ButtonState::Pressed); } - (void)rightMouseUp:(NSEvent *)event @@ -181,7 +181,7 @@ - (void)rightMouseUp:(NSEvent *)event ITT_FUNCTION_TASK(); assert(!!m_p_app); - m_p_app->InputController().OnMouseButtonChanged(Mouse::Button::Right, Mouse::ButtonState::Released); + m_p_app->InputState().OnMouseButtonChanged(Mouse::Button::Right, Mouse::ButtonState::Released); } - (void)rightMouseDragged:(NSEvent *)event @@ -195,7 +195,7 @@ - (void)otherMouseDown:(NSEvent *)event ITT_FUNCTION_TASK(); assert(!!m_p_app); - m_p_app->InputController().OnMouseButtonChanged(static_cast(static_cast([event buttonNumber])), Mouse::ButtonState::Pressed); + m_p_app->InputState().OnMouseButtonChanged(static_cast(static_cast([event buttonNumber])), Mouse::ButtonState::Pressed); } - (void)otherMouseUp:(NSEvent *)event @@ -203,7 +203,7 @@ - (void)otherMouseUp:(NSEvent *)event ITT_FUNCTION_TASK(); assert(!!m_p_app); - m_p_app->InputController().OnMouseButtonChanged(static_cast(static_cast([event buttonNumber])), Mouse::ButtonState::Released); + m_p_app->InputState().OnMouseButtonChanged(static_cast(static_cast([event buttonNumber])), Mouse::ButtonState::Released); } - (void)otherMouseDragged:(NSEvent *)event @@ -217,7 +217,7 @@ - (void)mouseEntered:(NSEvent *)event ITT_FUNCTION_TASK(); assert(!!m_p_app); - m_p_app->InputController().OnMouseInWindowChanged(true); + m_p_app->InputState().OnMouseInWindowChanged(true); } - (void)mouseExited:(NSEvent *)event @@ -225,7 +225,7 @@ - (void)mouseExited:(NSEvent *)event ITT_FUNCTION_TASK(); assert(!!m_p_app); - m_p_app->InputController().OnMouseInWindowChanged(false); + m_p_app->InputState().OnMouseInWindowChanged(false); } - (void)scrollWheel:(NSEvent *)event @@ -237,10 +237,10 @@ - (void)scrollWheel:(NSEvent *)event if ([event hasPreciseScrollingDeltas]) scroll *= 0.1f; - if (fabs(scroll.x()) < 0.00001 && fabs(scroll.y()) > 0.00001) + if (fabs(scroll.GetX()) < 0.00001 && fabs(scroll.GetY()) > 0.00001) return; - - m_p_app->InputController().OnMouseScrollChanged(scroll); + + m_p_app->InputState().OnMouseScrollChanged(scroll); } @end diff --git a/Modules/Platform/App/Sources/Methane/Platform/MacOS/WindowDelegate.hh b/Modules/Platform/App/Sources/Methane/Platform/MacOS/WindowDelegate.hh index 2394340bd..342fc50e7 100644 --- a/Modules/Platform/App/Sources/Methane/Platform/MacOS/WindowDelegate.hh +++ b/Modules/Platform/App/Sources/Methane/Platform/MacOS/WindowDelegate.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Platform/App/Sources/Methane/Platform/MacOS/WindowDelegate.mm b/Modules/Platform/App/Sources/Methane/Platform/MacOS/WindowDelegate.mm index ff692b624..5c30f205a 100644 --- a/Modules/Platform/App/Sources/Methane/Platform/MacOS/WindowDelegate.mm +++ b/Modules/Platform/App/Sources/Methane/Platform/MacOS/WindowDelegate.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ #import "WindowDelegate.hh" #include -#include +#include #include diff --git a/Modules/Platform/App/Sources/Methane/Platform/Windows/AppWin.cpp b/Modules/Platform/App/Sources/Methane/Platform/Windows/AppWin.cpp index a07eaa23f..a87750c22 100644 --- a/Modules/Platform/App/Sources/Methane/Platform/Windows/AppWin.cpp +++ b/Modules/Platform/App/Sources/Methane/Platform/Windows/AppWin.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ Windows application implementation. #include #include -#include +#include #include #include @@ -56,12 +56,6 @@ AppWin::AppWin(const AppBase::Settings& settings) ITT_FUNCTION_TASK(); } -void AppWin::ParseCommandLine(const cxxopts::ParseResult& cmd_parse_result) -{ - ITT_FUNCTION_TASK(); - AppBase::ParseCommandLine(cmd_parse_result); -} - int AppWin::Run(const RunArgs& args) { // Skip instrumentation ITT_FUNCTION_TASK() since this is the only root function running till application close @@ -85,11 +79,13 @@ int AppWin::Run(const RunArgs& args) uint32_t desktop_width = 0, desktop_height = 0; Methane::Platform::Windows::GetDesktopResolution(desktop_width, desktop_height); + const Settings& app_settings = GetPlatformAppSettings(); + Data::FrameSize frame_size; - frame_size.width = m_settings.width < 1.0 ? static_cast(desktop_width * (m_settings.width > 0.0 ? m_settings.width : 0.7)) - : static_cast(m_settings.width); - frame_size.height = m_settings.height < 1.0 ? static_cast(desktop_height * (m_settings.height > 0.0 ? m_settings.height : 0.7)) - : static_cast(m_settings.height); + frame_size.width = app_settings.width < 1.0 ? static_cast(desktop_width * (app_settings.width > 0.0 ? app_settings.width : 0.7)) + : static_cast(app_settings.width); + frame_size.height = app_settings.height < 1.0 ? static_cast(desktop_height * (app_settings.height > 0.0 ? app_settings.height : 0.7)) + : static_cast(app_settings.height); RECT window_rect = { 0, 0, static_cast(frame_size.width), static_cast(frame_size.height) }; AdjustWindowRect(&window_rect, WS_OVERLAPPEDWINDOW, FALSE); @@ -99,7 +95,7 @@ int AppWin::Run(const RunArgs& args) // Create the window and store a handle to it. m_env.window_handle = CreateWindowEx(NULL, g_window_class, - nowide::widen(m_settings.name).c_str(), + nowide::widen(app_settings.name).c_str(), WS_OVERLAPPEDWINDOW, (desktop_width - window_size.width) / 2, (desktop_height - window_size.height) / 2, @@ -266,19 +262,18 @@ LRESULT CALLBACK AppWin::WindowProc(HWND h_wnd, UINT msg_id, WPARAM w_param, LPA { // HACK: Release both Shift keys on Shift up event, as when both // are pressed the first release does not emit any event - // NOTE: The other half of this is in _glfwPlatformPollEvents - p_app->InputController().OnKeyboardChanged(Keyboard::Key::LeftShift, key_state); - p_app->InputController().OnKeyboardChanged(Keyboard::Key::RightShift, key_state); + p_app->InputState().OnKeyboardChanged(Keyboard::Key::LeftShift, key_state); + p_app->InputState().OnKeyboardChanged(Keyboard::Key::RightShift, key_state); } else if (w_param == VK_SNAPSHOT) { // HACK: Key down is not reported for the Print Screen key - p_app->InputController().OnKeyboardChanged(key, Keyboard::KeyState::Pressed); - p_app->InputController().OnKeyboardChanged(key, Keyboard::KeyState::Released); + p_app->InputState().OnKeyboardChanged(key, Keyboard::KeyState::Pressed); + p_app->InputState().OnKeyboardChanged(key, Keyboard::KeyState::Released); } else { - p_app->InputController().OnKeyboardChanged(key, key_state); + p_app->InputState().OnKeyboardChanged(key, key_state); } } break; @@ -291,7 +286,7 @@ LRESULT CALLBACK AppWin::WindowProc(HWND h_wnd, UINT msg_id, WPARAM w_param, LPA case WM_MBUTTONUP: case WM_XBUTTONUP: { - Mouse::Button button = Mouse::Button::Unknonwn; + Mouse::Button button = Mouse::Button::Unknown; if (msg_id == WM_LBUTTONDOWN || msg_id == WM_LBUTTONUP) button = Mouse::Button::Left; else if (msg_id == WM_RBUTTONDOWN || msg_id == WM_RBUTTONUP) @@ -313,7 +308,7 @@ LRESULT CALLBACK AppWin::WindowProc(HWND h_wnd, UINT msg_id, WPARAM w_param, LPA } p_app->m_mouse_state.SetButton(button, button_state); - p_app->InputController().OnMouseButtonChanged(button, button_state); + p_app->InputState().OnMouseButtonChanged(button, button_state); if (p_app->m_mouse_state.GetPressedButtons().empty()) { @@ -331,7 +326,7 @@ LRESULT CALLBACK AppWin::WindowProc(HWND h_wnd, UINT msg_id, WPARAM w_param, LPA const int x = GET_X_LPARAM(l_param); const int y = GET_Y_LPARAM(l_param); - p_app->InputController().OnMousePositionChanged({ x, y }); + p_app->InputState().OnMousePositionChanged({ x, y }); if (!p_app->GetInputState().GetMouseState().IsInWindow()) { @@ -343,7 +338,7 @@ LRESULT CALLBACK AppWin::WindowProc(HWND h_wnd, UINT msg_id, WPARAM w_param, LPA tme.hwndTrack = h_wnd; TrackMouseEvent(&tme); - p_app->InputController().OnMouseInWindowChanged(true); + p_app->InputState().OnMouseInWindowChanged(true); } return 0; @@ -351,14 +346,14 @@ LRESULT CALLBACK AppWin::WindowProc(HWND h_wnd, UINT msg_id, WPARAM w_param, LPA case WM_MOUSELEAVE: { - p_app->InputController().OnMouseInWindowChanged(false); + p_app->InputState().OnMouseInWindowChanged(false); return 0; } case WM_MOUSEWHEEL: { const float wheel_delta = static_cast(GET_WHEEL_DELTA_WPARAM(w_param)) / WHEEL_DELTA; - p_app->InputController().OnMouseScrollChanged({ 0.f, wheel_delta }); + p_app->InputState().OnMouseScrollChanged({ 0.f, wheel_delta }); return 0; } @@ -366,7 +361,7 @@ LRESULT CALLBACK AppWin::WindowProc(HWND h_wnd, UINT msg_id, WPARAM w_param, LPA { // NOTE: The X-axis is inverted for consistency with macOS and X11 const float wheel_delta = static_cast(GET_WHEEL_DELTA_WPARAM(w_param)) / WHEEL_DELTA; - p_app->InputController().OnMouseScrollChanged({ -wheel_delta, 0.f }); + p_app->InputState().OnMouseScrollChanged({ -wheel_delta, 0.f }); return 0; } @@ -391,7 +386,6 @@ void AppWin::ShowAlert(const Message& msg) { ITT_FUNCTION_TASK(); - UINT msgbox_type = 0; MessageBox( m_env.window_handle, nowide::widen(msg.information).c_str(), @@ -434,12 +428,13 @@ bool AppWin::SetFullScreen(bool is_full_screen) assert(!!m_env.window_handle); - RECT window_rect = {}; - int32_t window_style = WS_OVERLAPPEDWINDOW; - int32_t window_mode = 0; - HWND window_position = nullptr; + RECT window_rect = {}; + int32_t window_style = WS_OVERLAPPEDWINDOW; + int32_t window_mode = 0; + HWND window_position = nullptr; + const Settings& app_settings = GetPlatformAppSettings(); - if (m_settings.is_full_screen) + if (app_settings.is_full_screen) { GetWindowRect(m_env.window_handle, &m_window_rect); @@ -461,9 +456,6 @@ bool AppWin::SetFullScreen(bool is_full_screen) window_mode = SW_NORMAL; } - m_settings.width = window_rect.right - window_rect.left; - m_settings.height = window_rect.bottom - window_rect.top; - SetWindowLong(m_env.window_handle, GWL_STYLE, window_style); SetWindowPos(m_env.window_handle, window_position, window_rect.left, window_rect.top, diff --git a/Modules/Platform/AppView/CMakeLists.txt b/Modules/Platform/AppView/CMakeLists.txt index cc935ffbe..274ab2f21 100644 --- a/Modules/Platform/AppView/CMakeLists.txt +++ b/Modules/Platform/AppView/CMakeLists.txt @@ -58,7 +58,7 @@ add_library(${TARGET} STATIC target_link_libraries(${TARGET} ${LIBRARIES} - MethaneDataInstrumentation + MethaneInstrumentation ) target_include_directories(${TARGET} diff --git a/Modules/Platform/AppView/Include/Methane/Platform/AppEnvironment.h b/Modules/Platform/AppView/Include/Methane/Platform/AppEnvironment.h index c4ab8eec6..9daf74e5c 100644 --- a/Modules/Platform/AppView/Include/Methane/Platform/AppEnvironment.h +++ b/Modules/Platform/AppView/Include/Methane/Platform/AppEnvironment.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Platform/AppView/Include/Methane/Platform/AppView.h b/Modules/Platform/AppView/Include/Methane/Platform/AppView.h index 0da214818..fa6cd67cc 100644 --- a/Modules/Platform/AppView/Include/Methane/Platform/AppView.h +++ b/Modules/Platform/AppView/Include/Methane/Platform/AppView.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,7 +17,8 @@ limitations under the License. ******************************************************************************* FILE: Methane/Platform/AppView.h -Methane application view used both by Context in Core API and by Methane App implementations. +Methane application view used both by RenderContext in Core API +and by Methane App implementations. ******************************************************************************/ diff --git a/Modules/Platform/AppView/Include/Methane/Platform/Linux/AppEnvironment.h b/Modules/Platform/AppView/Include/Methane/Platform/Linux/AppEnvironment.h index ed215efc5..64815aa6b 100644 --- a/Modules/Platform/AppView/Include/Methane/Platform/Linux/AppEnvironment.h +++ b/Modules/Platform/AppView/Include/Methane/Platform/Linux/AppEnvironment.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Platform/AppView/Include/Methane/Platform/MacOS/AppEnvironment.hh b/Modules/Platform/AppView/Include/Methane/Platform/MacOS/AppEnvironment.hh index ce90854d4..b17db8be8 100644 --- a/Modules/Platform/AppView/Include/Methane/Platform/MacOS/AppEnvironment.hh +++ b/Modules/Platform/AppView/Include/Methane/Platform/MacOS/AppEnvironment.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Platform/AppView/Include/Methane/Platform/MacOS/AppViewMT.hh b/Modules/Platform/AppView/Include/Methane/Platform/MacOS/AppViewMT.hh index 840eabf20..de8024946 100644 --- a/Modules/Platform/AppView/Include/Methane/Platform/MacOS/AppViewMT.hh +++ b/Modules/Platform/AppView/Include/Methane/Platform/MacOS/AppViewMT.hh @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -54,6 +54,6 @@ MacOS application view implementation. pixelFormat:(MTLPixelFormat) pixelFormat drawableCount:(NSUInteger) drawable_count vsyncEnabled:(BOOL) vsync_enabled - unsyncRefreshInterval:(double) refresn_interval_sec; + unsyncRefreshInterval:(double) refresh_interval_sec; @end diff --git a/Modules/Platform/AppView/Include/Methane/Platform/Windows/AppEnvironment.h b/Modules/Platform/AppView/Include/Methane/Platform/Windows/AppEnvironment.h index a36bcfd39..609792d9d 100644 --- a/Modules/Platform/AppView/Include/Methane/Platform/Windows/AppEnvironment.h +++ b/Modules/Platform/AppView/Include/Methane/Platform/Windows/AppEnvironment.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Platform/AppView/Sources/Methane/Platform/AppView.cpp b/Modules/Platform/AppView/Sources/Methane/Platform/AppView.cpp index e2641b163..e14fbc7bb 100644 --- a/Modules/Platform/AppView/Sources/Methane/Platform/AppView.cpp +++ b/Modules/Platform/AppView/Sources/Methane/Platform/AppView.cpp @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Platform/AppView/Sources/Methane/Platform/MacOS/AppViewMT.mm b/Modules/Platform/AppView/Sources/Methane/Platform/MacOS/AppViewMT.mm index 1f3eb053a..4748ed21d 100644 --- a/Modules/Platform/AppView/Sources/Methane/Platform/MacOS/AppViewMT.mm +++ b/Modules/Platform/AppView/Sources/Methane/Platform/MacOS/AppViewMT.mm @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ #import -#include +#include @interface AppViewMT () { @@ -44,18 +44,18 @@ @implementation AppViewMT @synthesize vsyncEnabled = _vsyncEnabled; @synthesize unsyncRefreshInterval = _unsyncRefreshInterval; -CVDisplayLinkRef _displayLink; +CVDisplayLinkRef g_display_link; -static CVReturn OnDisplayLinkFrame(CVDisplayLinkRef displayLink, - const CVTimeStamp *now, - const CVTimeStamp *outputTime, - CVOptionFlags flagsIn, - CVOptionFlags *flagsOut, - void *displayLinkContext) +static CVReturn OnDisplayLinkFrame(CVDisplayLinkRef display_link, + const CVTimeStamp* /*now*/, + const CVTimeStamp* /*output_time*/, + CVOptionFlags /*flags_in*/, + CVOptionFlags* /*flags_out*/, + void* p_display_link_context) { ITT_FUNCTION_TASK(); - AppViewMT* app_view = (__bridge AppViewMT*)displayLinkContext; + AppViewMT* app_view = (__bridge AppViewMT*) p_display_link_context; if (app_view.redrawing) { @@ -90,7 +90,7 @@ - (instancetype) initWithFrame:(NSRect)backing_frame pixelFormat:(MTLPixelFormat) pixel_format drawableCount:(NSUInteger) drawable_count vsyncEnabled:(BOOL) vsync_enabled - unsyncRefreshInterval:(double) refresn_interval_sec + unsyncRefreshInterval:(double) refresh_interval_sec { ITT_FUNCTION_TASK(); @@ -103,7 +103,7 @@ - (instancetype) initWithFrame:(NSRect)backing_frame _pixelFormat = pixel_format; _drawableCount = drawable_count; _vsyncEnabled = vsync_enabled; - _unsyncRefreshInterval = refresn_interval_sec; + _unsyncRefreshInterval = refresh_interval_sec; [self updateTrackingAreas]; [self commonInit]; } @@ -127,8 +127,8 @@ - (void) commonInit self.wantsLayer = YES; self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay; - NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter]; - [notificationCenter addObserver:self + NSNotificationCenter* ns_notification_center = [NSNotificationCenter defaultCenter]; + [ns_notification_center addObserver:self selector:@selector(windowWillClose:) name:NSWindowWillCloseNotification object:self.window]; @@ -250,16 +250,16 @@ - (void) setRedrawing: (BOOL) redrawing { if (_vsyncEnabled) { - CVReturn cvReturn = CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink); - assert(cvReturn == kCVReturnSuccess); - - cvReturn = CVDisplayLinkSetOutputCallback(_displayLink, &OnDisplayLinkFrame, (__bridge void *)self); - assert(cvReturn == kCVReturnSuccess); - - cvReturn = CVDisplayLinkSetCurrentCGDisplay(_displayLink, CGMainDisplayID()); - assert(cvReturn == kCVReturnSuccess); + CVReturn cv_return = CVDisplayLinkCreateWithActiveCGDisplays(&g_display_link); + assert(cv_return == kCVReturnSuccess); + + cv_return = CVDisplayLinkSetOutputCallback(g_display_link, &OnDisplayLinkFrame, (__bridge void *)self); + assert(cv_return == kCVReturnSuccess); + + cv_return = CVDisplayLinkSetCurrentCGDisplay(g_display_link, CGMainDisplayID()); + assert(cv_return == kCVReturnSuccess); - CVDisplayLinkStart(_displayLink); + CVDisplayLinkStart(g_display_link); } else { @@ -267,12 +267,12 @@ - (void) setRedrawing: (BOOL) redrawing self.unsyncTimer = [NSTimer scheduledTimerWithTimeInterval:_unsyncRefreshInterval target:self selector:@selector(redraw) userInfo:nil repeats:YES]; } } - else if (_displayLink) + else if (g_display_link) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; - CVDisplayLinkStop(_displayLink); - CVDisplayLinkRelease(_displayLink); - _displayLink = nil; + CVDisplayLinkStop(g_display_link); + CVDisplayLinkRelease(g_display_link); + g_display_link = nil; } } @@ -282,9 +282,9 @@ - (void) redraw if (!self.redrawing) return; - bool delegateCanDrawInView = [self.delegate respondsToSelector:@selector(drawInView:)]; - assert(delegateCanDrawInView); - if (!delegateCanDrawInView) + bool delegate_can_draw_in_view = [self.delegate respondsToSelector:@selector(drawInView:)]; + assert(delegate_can_draw_in_view); + if (!delegate_can_draw_in_view) return; self.currentDrawable = [self.metalLayer nextDrawable]; @@ -297,7 +297,7 @@ - (void) windowWillClose:(NSNotification*)notification // Stop the display link when the window is closing because we will // not be able to get a drawable, but the display link may continue to fire - if (notification.object == self.window && _displayLink) + if (notification.object == self.window && g_display_link) { self.redrawing = NO; } @@ -308,8 +308,8 @@ - (void)setViewController:(NSViewController *)newController ITT_FUNCTION_TASK(); if (viewController) { - NSResponder *controllerNextResponder = [viewController nextResponder]; - [super setNextResponder:controllerNextResponder]; + NSResponder* controller_next_responder = [viewController nextResponder]; + [super setNextResponder:controller_next_responder]; [viewController setNextResponder:nil]; } @@ -317,9 +317,9 @@ - (void)setViewController:(NSViewController *)newController if (newController) { - NSResponder *ownNextResponder = [self nextResponder]; + NSResponder* own_next_responder = [self nextResponder]; [super setNextResponder: viewController]; - [viewController setNextResponder:ownNextResponder]; + [viewController setNextResponder:own_next_responder]; } } diff --git a/Modules/Platform/Input/CMakeLists.txt b/Modules/Platform/Input/CMakeLists.txt index a43ed5b48..9b024c863 100644 --- a/Modules/Platform/Input/CMakeLists.txt +++ b/Modules/Platform/Input/CMakeLists.txt @@ -13,9 +13,10 @@ if(APPLE) endif() set(LIBRARIES ${LIBRARIES} + MethaneCommonPrimitives MethaneDataPrimitives MethanePlatformUtils - MethaneDataInstrumentation + MethaneInstrumentation ) set(HEADERS diff --git a/Modules/Platform/Input/Include/Methane/Platform/Input/Controller.h b/Modules/Platform/Input/Include/Methane/Platform/Input/Controller.h index ee3c0845b..599724d1b 100644 --- a/Modules/Platform/Input/Include/Methane/Platform/Input/Controller.h +++ b/Modules/Platform/Input/Include/Methane/Platform/Input/Controller.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,9 +28,6 @@ Abstract input controller interface for handling keyboard and mouse actions. #include #include -#include -#include - namespace Methane::Platform::Input { @@ -63,8 +60,6 @@ class Controller , public IHelpProvider { public: - using Ptr = std::shared_ptr; - Controller(const std::string& name) : m_name(name) { } const std::string& GetControllerName() const { return m_name; } @@ -87,6 +82,4 @@ class Controller bool m_is_enabled = true; }; -using Controllers = std::vector; - } // namespace Methane::Platform::Input diff --git a/Modules/Platform/Input/Include/Methane/Platform/Input/ControllersPool.h b/Modules/Platform/Input/Include/Methane/Platform/Input/ControllersPool.h index f6c5a491d..0d97f37c4 100644 --- a/Modules/Platform/Input/Include/Methane/Platform/Input/ControllersPool.h +++ b/Modules/Platform/Input/Include/Methane/Platform/Input/ControllersPool.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,17 +25,19 @@ A pool of input controllers for user actions handling in separate application co #include "Controller.h" +#include + namespace Methane::Platform::Input { class ControllersPool - : public Controllers + : public Ptrs , public IController , public IHelpProvider { public: - using Controllers::Controllers; - using Controllers::operator=; + using Ptrs::Ptrs; + using Ptrs::operator=; // IController implementation void OnMouseButtonChanged(Mouse::Button button, Mouse::ButtonState button_state, const Mouse::StateChange& state_change) override; diff --git a/Modules/Platform/Input/Include/Methane/Platform/Input/HelpProvider.h b/Modules/Platform/Input/Include/Methane/Platform/Input/HelpProvider.h index d750e9822..6afd2b36c 100644 --- a/Modules/Platform/Input/Include/Methane/Platform/Input/HelpProvider.h +++ b/Modules/Platform/Input/Include/Methane/Platform/Input/HelpProvider.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Platform/Input/Include/Methane/Platform/Input/State.h b/Modules/Platform/Input/Include/Methane/Platform/Input/State.h index e3d023c4f..bececb64e 100644 --- a/Modules/Platform/Input/Include/Methane/Platform/Input/State.h +++ b/Modules/Platform/Input/Include/Methane/Platform/Input/State.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,6 +25,8 @@ Aggregated application input state with controllers. #include "ControllersPool.h" +#include + namespace Methane::Platform::Input { @@ -34,11 +36,11 @@ class State : public IActionController State() = default; State(const ControllersPool& controllers) : m_controllers(controllers) {} - const ControllersPool& GetControllers() const { return m_controllers; } - void AddControllers(const Controllers& controllers) { m_controllers.insert(m_controllers.end(), controllers.begin(), controllers.end()); } + const ControllersPool& GetControllers() const noexcept { return m_controllers; } + void AddControllers(const Ptrs& controllers) { m_controllers.insert(m_controllers.end(), controllers.begin(), controllers.end()); } - const Keyboard::State& GetKeyboardState() const { return m_keyboard_state; } - const Mouse::State& GetMouseState() const { return m_mouse_state; } + const Keyboard::State& GetKeyboardState() const noexcept { return m_keyboard_state; } + const Mouse::State& GetMouseState() const noexcept { return m_mouse_state; } // IActionController void OnMouseButtonChanged(Mouse::Button button, Mouse::ButtonState button_state) override; @@ -50,6 +52,23 @@ class State : public IActionController void ReleaseAllKeys(); + template>> + Refs GetControllersOfType() const + { + ITT_FUNCTION_TASK(); + Refs controllers; + const std::type_info& controller_type = typeid(ControllerT); + for(const Ptr& sp_controller : m_controllers) + { + if (!sp_controller) + continue; + Controller& controller = *sp_controller; + if (typeid(controller) == controller_type) + controllers.emplace_back(static_cast(*sp_controller)); + } + return controllers; + } + protected: ControllersPool m_controllers; Mouse::State m_mouse_state; diff --git a/Modules/Platform/Input/Include/Methane/Platform/Keyboard.h b/Modules/Platform/Input/Include/Methane/Platform/Keyboard.h index 231c61456..d38c1ff32 100644 --- a/Modules/Platform/Input/Include/Methane/Platform/Keyboard.h +++ b/Modules/Platform/Input/Include/Methane/Platform/Keyboard.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -91,13 +91,13 @@ namespace OS { #ifdef __APPLE__ -constexpr Key key_left_ctrl = Key::LeftSuper; -constexpr Key key_right_ctrl = Key::RightSuper; +constexpr Key g_key_left_ctrl = Key::LeftSuper; +constexpr Key g_key_right_ctrl = Key::RightSuper; #else -constexpr Key key_left_ctrl = Key::LeftControl; -constexpr Key key_right_ctrl = Key::RightControl; +constexpr Key g_key_left_ctrl = Key::LeftControl; +constexpr Key g_key_right_ctrl = Key::RightControl; #endif } diff --git a/Modules/Platform/Input/Include/Methane/Platform/KeyboardActionControllerBase.hpp b/Modules/Platform/Input/Include/Methane/Platform/KeyboardActionControllerBase.hpp index 64440201c..46aa046ff 100644 --- a/Modules/Platform/Input/Include/Methane/Platform/KeyboardActionControllerBase.hpp +++ b/Modules/Platform/Input/Include/Methane/Platform/KeyboardActionControllerBase.hpp @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright 2019 Evgeny Gorodetskiy + Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ #include "Input/HelpProvider.h" #include "Keyboard.h" -#include +#include #include diff --git a/Modules/Platform/Input/Include/Methane/Platform/Linux/Keyboard.h b/Modules/Platform/Input/Include/Methane/Platform/Linux/Keyboard.h index 329f5bd04..5954f10a5 100644 --- a/Modules/Platform/Input/Include/Methane/Platform/Linux/Keyboard.h +++ b/Modules/Platform/Input/Include/Methane/Platform/Linux/Keyboard.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Platform/Input/Include/Methane/Platform/MacOS/Keyboard.h b/Modules/Platform/Input/Include/Methane/Platform/MacOS/Keyboard.h index 87ee49652..e0d593912 100644 --- a/Modules/Platform/Input/Include/Methane/Platform/MacOS/Keyboard.h +++ b/Modules/Platform/Input/Include/Methane/Platform/MacOS/Keyboard.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Modules/Platform/Input/Include/Methane/Platform/Mouse.h b/Modules/Platform/Input/Include/Methane/Platform/Mouse.h index 571b365b0..a4e09799a 100644 --- a/Modules/Platform/Input/Include/Methane/Platform/Mouse.h +++ b/Modules/Platform/Input/Include/Methane/Platform/Mouse.h @@ -1,6 +1,6 @@ /****************************************************************************** -Copyright 2019 Evgeny Gorodetskiy +Copyright 2019-2020 Evgeny Gorodetskiy Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -48,7 +48,7 @@ enum class Button : uint32_t HScroll, Count, - Unknonwn + Unknown }; using Buttons = std::set