Methane Kit
Easy to use modern 3D graphics abstraction API written in C++ for cross-platform applications development:
- Built on top of modern native 3D graphics APIs: DirectX 12 on Windows and Metal on MacOS.
- Provides object-oriented graphics API simple but capable of high-performance graphics rendering on modern GPUs.
- Supplies completely cross-platform application infrastructure: clean C++ code without nasty preprocessor stuff.
Note that project is in Alpha / MVP stage and is under active development.
Features
- Cross-platform
- Supported platforms:
- Windows 10 with DirectX 12
- MacOS (El Capitan or later) with Metal API
- Application infrastructure:
- Methane CMake module is provided to simplify configuration of the application build
- Base application class and platform-specific implementations are completely GLFW free
- Graphics application base template class with basic multi-frame swap-chain management
- Supported platforms:
- One shader code for all APIs
- Shaders are written in HLSL 5.1
- Shaders are converted to native API shading language at build time with SPIRV-Cross toolchain
- Shaders are prebuilt and embedded in application resources as bytecode (with preprocessor definitions support)
- Easy to use object-oriented graphics API
- Core graphics interfaces:
- Context unifies Device and Swap-Chain under one umbrella
- Resource derived interfaces Buffer, Texture, Sampler to work with GPU memory resources
- Shader and Program providing unified access to compiled shaders, input layout and uniform variables
- Program::ResourceBindings simplifies binding resources to programs by uniform variable names and enables fast bindings switching at runtime
- RenderState and RenderPass used for inputs and outputs configuration of the graphics pipeline
- RenderCommandList and CommandQueue for render commands encoding and execution
- Core interface extensions like: ImageLoader for creating textures from common image formats.
- Common 3D graphics helpers like: Camera, Timer, Mesh generator, etc.
- Core graphics interfaces:
- Lightweight:
- No heavy external depedencies (almost all libraries are header only)
- Fast application startup (thanks to embedded prebuilt shaders)
- Performance oriented:
- Triple frame buffering is used by default (work in progress)
- Builtin API instrumentation with Intel ITT API to simplify performance analysis with Intel Vtune Amplifier and Intel Graphics Trace Analyzer
Development plans
- Continous integration with Travis on GitHub
- Application user input with mouse and keyboard
- Text rendering
- User interface library
- Improved shader conversion
- Dynamic linking support
- Compute pipeline
- Parallel command lists
Getting Started
Prerequisites
- Common
- Git
- CMake 3.12 or later installed and availabled from any location
- Windows
- Windows 10 OS or later
- Visual Studio 2017 or later
- MSVC v141 or later
- Windows 10 SDK
- MacOS
- MacOS El Capitan OS or later
- XCode with Command Line tools
Build
Fetch Sources
IMPORTANT: Do not download source code via Zip archive, since it will not allow to properly initalize External submodules. Use git as described below.
- First time initialization
mkdir <MethaneKit-Root>
cd <MethaneKit-Root>
git clone --recurse-submodules --depth 1 https://github.com/egorodet/MethaneKit.git
- Update sources to latest version
cd <MethaneKit-Root>
git pull --recurse-submodules
- Update linked submodules to latest version (for development purposes only)
cd <MethaneKit-Root>
git submodule update --init --depth 1 --recursive
git pull --recurse-submodules
Windows Build
Start "x64 Native Tools Command Prompt for VS2017" (it initializes environment with VS path to Windows SDK, etc), then go to MethaneKit root directory (see instructions above to initialize repository and get latest code with submodules) and either start auxilarry build script Build/Windows/Build.bat or build with cmake manually:
mkdir Build\Output\VisualStudio\Build
cd Build\Output\VisualStudio\Build
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_INSTALL_PREFIX="%cd%\..\Install" "..\..\..\.."
cmake --build . --config Release --target install
Alternatively you can open root CMakeLists.txt directly in Visual Studio 2017 and build it with VS CMake Tools using "Ninja" generator and provided configuration file CMakeSettings.json.
Run tutorials from the installation directory Build\Output\VisualStudio\Install\Apps\Tutorials
.
MacOS Build
Start terminal, then go to MethaneKit root directory (see instructions above to initialize repository and get latest code with submodules) and either start auxilarry build script Build/MacOS/Build.sh or build with cmake manually:
mkdir -p Build/Output/XCode/Build
cd Build/Output/XCode/Build
cmake -H../../../.. -B. -G Xcode -DCMAKE_INSTALL_PREFIX="$(pwd)/../Install"
cmake --build . --config Release --target install
Alternatively you can open root CMakeLists.txt directly in QtCreator or VSCode or any other IDE of choice and build it from there.
Run tutorials from the installation directory Build/Output/XCode/Install/Apps/Tutorials
Tutorials
Tutorial / Platform | Windows (DirectX 12) | MacOS (Metal) |
---|---|---|
Hello Triangle | ||
Textured Cube | ||
Shadow Cube |
Hello Triangle
See how triangle rendering application is implemented in 120 lines of C++ code using Methane Kit (HelloTriangleAppSimple.cpp):
#include <Methane/Kit.h>
using namespace Methane;
using namespace Methane::Graphics;
struct HelloTriangleFrame final : AppFrame
{
RenderCommandList::Ptr sp_cmd_list;
using AppFrame::AppFrame;
};
using GraphicsApp = App<HelloTriangleFrame>;
class HelloTriangleApp final : public GraphicsApp
{
private:
RenderState::Ptr m_sp_state;
Buffer::Ptr m_sp_vertex_buffer;
public:
HelloTriangleApp() : GraphicsApp(
{ // Application settings:
{ // app:
"Methane Hello Triangle", // - name
0.8, 0.8, // - width, height
}, //
{ // context:
FrameSize(), // - frame_size placeholder: actual size is set in InitContext
PixelFormat::BGRA8Unorm, // - color_format
PixelFormat::Unknown, // - depth_stencil_format
Color(0.0f, 0.2f, 0.4f, 1.0f), // - clear_color
}, //
true // show_hud_in_window_title
},
RenderPass::Access::None) // screen_pass_access (program access to resources)
{ }
~HelloTriangleApp() override
{
m_sp_context->WaitForGpu(Context::WaitFor::RenderComplete);
}
void Init() override
{
GraphicsApp::Init();
struct Vertex { Vector3f position; Vector3f color; };
const std::array<Vertex, 3> triange_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<Data::Size>(sizeof(triange_vertices));
m_sp_vertex_buffer = Buffer::CreateVertexBuffer(*m_sp_context, vertex_buffer_size, static_cast<Data::Size>(sizeof(Vertex)));
m_sp_vertex_buffer->SetData(reinterpret_cast<Data::ConstRawPtr>(triange_vertices.data()), vertex_buffer_size);
m_sp_state = RenderState::Create(*m_sp_context,
{
Program::Create(*m_sp_context, {
{
Shader::CreateVertex(*m_sp_context, { { "VSMain", "vs_5_1" } }),
Shader::CreatePixel(*m_sp_context, { { "PSMain", "ps_5_1" } }),
},
{ { {
{ "in_position", "POSITION" },
{ "in_color", "COLOR" },
} } },
{ },
{ m_sp_context->GetSettings().color_format }
}),
{ GetFrameViewport(m_sp_context->GetSettings().frame_size) },
{ GetFrameScissorRect(m_sp_context->GetSettings().frame_size) },
});
for (HelloTriangleFrame& frame : m_frames)
{
frame.sp_cmd_list = RenderCommandList::Create(m_sp_context->GetRenderCommandQueue(), *frame.sp_screen_pass);
}
m_sp_context->CompleteInitialization();
}
bool Resize(const FrameSize& frame_size, bool is_minimized) override
{
if (!GraphicsApp::Resize(frame_size, is_minimized))
return false;
m_sp_state->SetViewports( { GetFrameViewport(frame_size) } );
m_sp_state->SetScissorRects( { GetFrameScissorRect(frame_size) } );
return true;
}
void Update() override { }
void Render() override
{
if (HasError() || !m_sp_context->ReadyToRender())
return;
m_sp_context->WaitForGpu(Context::WaitFor::FramePresented);
HelloTriangleFrame & frame = GetCurrentFrame();
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, 1);
frame.sp_cmd_list->Commit(true);
m_sp_context->GetRenderCommandQueue().Execute({ *frame.sp_cmd_list });
m_sp_context->Present();
GraphicsApp::Render();
}
};
int main(int argc, const char* argv[])
{
return HelloTriangleApp().Run({ argc, argv });
}
Also you need a simple HLSL shader Shaders/Shaders.hlsl.
Note how arguments of verftex shader function VSMain(...)
are matching to input buffer layout description passed in Settings of Program::Create(...)
call:
struct PSInput
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
PSInput VSMain(float3 in_position : POSITION,
float3 in_color : COLOR)
{
PSInput output;
output.position = float4(in_position, 1.0f);
output.color = float4(in_color, 1.0f);
return output;
}
float4 PSMain(PSInput input) : SV_TARGET
{
return input.color;
}
The configuration file Shaders/Shaders.cfg describes shader types along with entry points and optional sets of macro definitions used to prebuild shaders to bytecode:
frag=PSMain
vert=VSMain
Finally add build configuration CMakeLists.txt powered by included module Methane.cmake:
include(Methane)
add_methane_application(MethaneHelloTriangle
"Methane Hello Triangle"
"HelloTriangleAppSimple.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/Shaders/Shaders.hlsl"
"${CMAKE_CURRENT_SOURCE_DIR}/Shaders/Shaders.cfg"
"" # RESOURCES_DIR
"" # EMBEDDED_TEXTURES_DIR
"" # EMBEDDED_TEXTURES
"" # COPY_TEXTURES
"Apps/Tutorials" # INSTALL_DIR
)
Now you have all in one application executable/bundle running on Windows/MacOS, which is rendering colored triangle in window with support of resizing the frame buffer.
External Dependencies
All external dependencies of Methane Kit are gathered in MethaneExternals repository. See MethaneExternals/README.md for more details.
License
Methane Kit is distributed under Apache 2.0 License: it is free to use and open for contribution!