├── .gitmodules
├── .travis.yml
├── CMakeLists.txt
├── README.md
├── demos
├── 01_clear_screen.cpp
├── 02_triangle_shared.cpp
├── 03_triangle_staged.cpp
├── 04_triangle_recorded.cpp
├── 05_spinny_double.cpp
├── 06_spinny_staged.cpp
├── 07_hello_texture.cpp
├── 08_klein_bottle.cpp
├── 09_particle_system.cpp
├── 0a_particle_system.cpp
├── 0b_shadertoy.cpp
├── 0c_framebuffer.cpp
├── CMakeLists.txt
└── README.md
├── docs
├── apidoc.css
├── index.html
├── lavadoc.md.html
└── markdeep.min.js
├── extras
├── android
│ ├── .gitignore
│ ├── README.md
│ ├── app
│ │ ├── CMakeLists.txt
│ │ ├── build.gradle
│ │ ├── lava
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── cpp
│ │ │ ├── ClearScreenApp.cpp
│ │ │ └── TriangleRecordedApp.cpp
│ │ │ └── res
│ │ │ └── values
│ │ │ └── strings.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ └── settings.gradle
├── assets
│ ├── abstract.jpg
│ ├── icon.png
│ ├── klein.c
│ ├── klein.glsl
│ ├── klein.obj
│ ├── klein31416.gif
│ ├── particles1.png
│ ├── particles2.jpg
│ ├── particles3.jpg
│ ├── rust.png
│ └── triptych.png
├── macos
│ ├── CMakeLists.txt
│ ├── README.md
│ ├── aliases.sh
│ ├── lava
│ └── src
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.mm
│ │ ├── GameViewController.h
│ │ ├── GameViewController.mm
│ │ ├── MainMenu.xib
│ │ ├── Shaders.metal
│ │ ├── SharedStructures.h
│ │ ├── main.mm
│ │ ├── plist.in
│ │ └── test.cpp
├── todo.md
├── vmath.h
└── vscode
│ ├── c_cpp_properties.json
│ └── settings.json
├── include
├── par
│ ├── AmberApplication.h
│ ├── AmberCompiler.h
│ ├── AmberProgram.h
│ ├── LavaContext.h
│ ├── LavaCpuBuffer.h
│ ├── LavaDescCache.h
│ ├── LavaGpuBuffer.h
│ ├── LavaLoader.h
│ ├── LavaLog.h
│ ├── LavaPipeCache.h
│ ├── LavaSurfCache.h
│ └── LavaTexture.h
├── spdlog
│ ├── async_logger.h
│ ├── common.h
│ ├── contrib
│ │ ├── README.md
│ │ └── sinks
│ │ │ ├── .gitignore
│ │ │ └── step_file_sink.h
│ ├── details
│ │ ├── async_log_helper.h
│ │ ├── async_logger_impl.h
│ │ ├── file_helper.h
│ │ ├── log_msg.h
│ │ ├── logger_impl.h
│ │ ├── mpmc_bounded_q.h
│ │ ├── null_mutex.h
│ │ ├── os.h
│ │ ├── pattern_formatter_impl.h
│ │ ├── registry.h
│ │ └── spdlog_impl.h
│ ├── fmt
│ │ ├── bundled
│ │ │ ├── LICENSE.rst
│ │ │ ├── format.cc
│ │ │ ├── format.h
│ │ │ ├── ostream.cc
│ │ │ ├── ostream.h
│ │ │ ├── posix.cc
│ │ │ ├── posix.h
│ │ │ ├── printf.cc
│ │ │ ├── printf.h
│ │ │ └── time.h
│ │ ├── fmt.h
│ │ └── ostr.h
│ ├── formatter.h
│ ├── logger.h
│ ├── sinks
│ │ ├── android_sink.h
│ │ ├── ansicolor_sink.h
│ │ ├── base_sink.h
│ │ ├── dist_sink.h
│ │ ├── file_sinks.h
│ │ ├── msvc_sink.h
│ │ ├── null_sink.h
│ │ ├── ostream_sink.h
│ │ ├── sink.h
│ │ ├── stdout_sinks.h
│ │ ├── syslog_sink.h
│ │ ├── wincolor_sink.h
│ │ └── windebug_sink.h
│ ├── spdlog.h
│ └── tweakme.h
└── vulkan
│ ├── vk_platform.h
│ ├── vulkan.h
│ ├── vulkan_android.h
│ ├── vulkan_core.h
│ └── vulkan_macos.h
└── src
├── AmberCompiler.cpp
├── AmberMain.cpp
├── AmberProgram.cpp
├── LavaContext.cpp
├── LavaCpuBuffer.cpp
├── LavaDescCache.cpp
├── LavaGpuBuffer.cpp
├── LavaInternal.cpp
├── LavaInternal.h
├── LavaLoader.cpp
├── LavaLog.cpp
├── LavaPipeCache.cpp
├── LavaSurfCache.cpp
├── LavaTexture.cpp
└── vk_mem_alloc.h
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "extras/glfw"]
2 | path = extras/glfw
3 | url = https://github.com/glfw/glfw.git
4 | [submodule "extras/glslang"]
5 | path = extras/glslang
6 | url = https://github.com/KhronosGroup/glslang.git
7 | [submodule "extras/stb"]
8 | path = extras/stb
9 | url = https://github.com/nothings/stb.git
10 | [submodule "extras/par"]
11 | path = extras/par
12 | url = https://github.com/prideout/par
13 | [submodule "extras/tinyobjloader"]
14 | path = extras/tinyobjloader
15 | url = https://github.com/syoyo/tinyobjloader
16 | [submodule "extras/SimpleFileWatcher"]
17 | path = extras/SimpleFileWatcher
18 | url = https://github.com/skogler/SimpleFileWatcher.git
19 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 |
3 | compiler: clang
4 |
5 | git:
6 | submodules: false
7 |
8 | os:
9 | - linux
10 | - osx
11 |
12 | addons:
13 | apt:
14 | packages:
15 | - libxrandr-dev
16 | - libxinerama-dev
17 | - libxcursor-dev
18 | - libxi-dev
19 |
20 | script:
21 | - cmake . -B.core && cmake --build .core
22 | - git submodule update --init
23 | - cmake . -B.demos && cmake --build .demos
24 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then cd extras/macos ; fi
25 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then cmake -H. -B_build -GXcode ; fi
26 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then cmake --build _build ; fi
27 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.6)
2 |
3 | project(Lava)
4 |
5 | # To override the Debug build type, invoke cmake with -DCMAKE_BUILD_TYPE=Release
6 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
7 | message(STATUS "Setting build type to 'Debug' as none was specified.")
8 | set(CMAKE_BUILD_TYPE "Debug")
9 | endif()
10 |
11 | # Note that -fsanitize=undefined is also an interesting option.
12 | # -fsanitize=leak is also interesting, but not yet supported on MacOS.
13 | # set(EXTRA_SANITIZE_OPTIONS "-fsanitize=address")
14 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${EXTRA_SANITIZE_OPTIONS}")
15 | set(CMAKE_CXX_FLAGS "-std=c++14 -stdlib=libc++ -fno-rtti")
16 |
17 | # If submodules have been initialized, then build demo dependencies.
18 | if(EXISTS "${CMAKE_SOURCE_DIR}/extras/glfw/CMakeLists.txt")
19 | add_subdirectory(extras/glfw)
20 | add_subdirectory(extras/glslang)
21 | add_subdirectory(extras/SimpleFileWatcher)
22 | endif()
23 |
24 | # Build the core library (zero dependencies).
25 | include_directories(include)
26 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
27 |
28 | set(LAVA_SOURCE
29 | src/LavaContext.cpp
30 | src/LavaCpuBuffer.cpp
31 | src/LavaDescCache.cpp
32 | src/LavaGpuBuffer.cpp
33 | src/LavaInternal.cpp
34 | src/LavaLoader.cpp
35 | src/LavaLog.cpp
36 | src/LavaSurfCache.cpp
37 | src/LavaPipeCache.cpp
38 | src/LavaTexture.cpp)
39 |
40 | if(AMBER_REQUIRED)
41 | set(AMBER_SOURCE
42 | ${CMAKE_CURRENT_SOURCE_DIR}/src/AmberMain.cpp
43 | ${CMAKE_CURRENT_SOURCE_DIR}/src/AmberCompiler.cpp
44 | ${CMAKE_CURRENT_SOURCE_DIR}/src/AmberProgram.cpp PARENT_SCOPE)
45 | endif()
46 |
47 | add_library(lava STATIC ${LAVA_SOURCE})
48 |
49 | # Build demos if submodules have been initialized.
50 | if(EXISTS "${CMAKE_SOURCE_DIR}/extras/glfw/CMakeLists.txt")
51 | add_subdirectory(demos)
52 | endif()
53 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | [](https://travis-ci.org/prideout/lava)
4 |
5 | *Lava is just an experimental playground, I do not recommend using it in a production
6 | setting.*
7 |
8 | **Lava** is a toy C++ library composed of classes that make it easy to create and manage Vulkan
9 | objects. Each Lava class is defined by a single header with no dependencies on anything other than
10 | `vulkan.h` and the STL.
11 |
12 | For more information, see the [documentation](https://prideout.net/lava/).
13 |
14 | ## Scope
15 |
16 | Lava does not include a materials system, a scene graph, an asset loader, or any
17 | platform-specific functionality like windowing and events.
18 |
19 | Lava is implemented with a subset of C++14 that forbids RTTI, exceptions, and the use of
20 | ``. The public API uses a very narrow subset of C++ whereby classes contain nothing but
21 | methods.
22 |
23 | The core library has no dependencies on any third-party libraries other than the single-file
24 | [vk_mem_alloc.h](src/vk_mem_alloc.h) library and [spdlog](https://github.com/gabime/spdlog), which
25 | are included in the repo for convenience.
26 |
27 | ## Supported platforms
28 |
29 | Lava supports macOS via MoltenVK, as well as Linux and Android. It should be easy to extend to other
30 | platforms in the future.
31 |
--------------------------------------------------------------------------------
/demos/01_clear_screen.cpp:
--------------------------------------------------------------------------------
1 | // The MIT License
2 | // Copyright (c) 2018 Philip Rideout
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | using namespace par;
12 |
13 | static constexpr int DEMO_WIDTH = 640;
14 | static constexpr int DEMO_HEIGHT = 480;
15 |
16 | static const std::string vertShaderGLSL = AMBER_PREFIX_450 R"GLSL(
17 | layout(location=0) in vec4 position;
18 | layout(location=1) in vec2 uv;
19 | layout(location=0) out vec2 TexCoord;
20 | void main() {
21 | gl_Position = position;
22 | TexCoord = uv;
23 | }
24 | )GLSL";
25 |
26 | static const std::string fragShaderGLSL = AMBER_PREFIX_450 R"GLSL(
27 | layout(location=0) out vec4 Color;
28 | layout(location=0) in vec2 uv;
29 | layout(binding=0, set=0) uniform sampler2D tex;
30 | void main() {
31 | Color = texture(tex, uv);
32 | }
33 | )GLSL";
34 |
35 | int main(const int argc, const char *argv[]) {
36 | // Initialize GLFW.
37 | glfwSetErrorCallback([] (int error, const char* description) {
38 | llog.error(description);
39 | });
40 | LOG_CHECK(glfwInit(), "Cannot initialize GLFW.");
41 |
42 | // Create the window.
43 | glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
44 | glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
45 | glfwWindowHint(GLFW_DECORATED, GL_FALSE);
46 | GLFWwindow* window = glfwCreateWindow(DEMO_WIDTH, DEMO_HEIGHT, "shadertest", 0, 0);
47 | if (!window) {
48 | llog.fatal("Cannot create a window in which to draw!");
49 | }
50 |
51 | // Allow the Escape key to quit.
52 | glfwSetKeyCallback(window, [] (GLFWwindow* window, int key, int, int action, int) {
53 | if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) {
54 | glfwSetWindowShouldClose(window, GLFW_TRUE);
55 | }
56 | });
57 |
58 | // Create the VkInstance, VkDevice, etc.
59 | auto context = LavaContext::create({
60 | .depthBuffer = false,
61 | .validation = true,
62 | .samples = VK_SAMPLE_COUNT_1_BIT,
63 | .createSurface = [window] (VkInstance instance) {
64 | VkSurfaceKHR surface;
65 | glfwCreateWindowSurface(instance, window, nullptr, &surface);
66 | return surface;
67 | }
68 | });
69 | VkDevice device = context->getDevice();
70 |
71 | // Compile shaders.
72 | auto program = AmberProgram::create(vertShaderGLSL, fragShaderGLSL);
73 | program->compile(device);
74 |
75 | // Main game loop.
76 | while (!glfwWindowShouldClose(window)) {
77 | glfwPollEvents();
78 |
79 | // Start the command buffer and begin the render pass.
80 | VkCommandBuffer cmdbuffer = context->beginFrame();
81 | const float red = fmod(glfwGetTime(), 1.0);
82 | const VkClearValue clearValue = { .color.float32 = {red, 0, 0, 1} };
83 | const VkRenderPassBeginInfo rpbi {
84 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
85 | .framebuffer = context->getFramebuffer(),
86 | .renderPass = context->getRenderPass(),
87 | .renderArea.extent.width = context->getSize().width,
88 | .renderArea.extent.height = context->getSize().height,
89 | .pClearValues = &clearValue,
90 | .clearValueCount = 1
91 | };
92 | vkCmdBeginRenderPass(cmdbuffer, &rpbi, VK_SUBPASS_CONTENTS_INLINE);
93 |
94 | // ...do not draw any geometry...
95 |
96 | // End the render pass, flush the command buffer, and present the backbuffer.
97 | vkCmdEndRenderPass(cmdbuffer);
98 | context->endFrame();
99 | }
100 |
101 | // Cleanup.
102 | delete program;
103 | delete context;
104 | return 0;
105 | }
106 |
--------------------------------------------------------------------------------
/demos/02_triangle_shared.cpp:
--------------------------------------------------------------------------------
1 | // The MIT License
2 | // Copyright (c) 2018 Philip Rideout
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include
11 |
12 | #include
13 |
14 | using namespace par;
15 |
16 | static constexpr int DEMO_WIDTH = 512;
17 | static constexpr int DEMO_HEIGHT = 512;
18 | static constexpr float PI = 3.1415926535;
19 |
20 | static const std::string vertShaderGLSL = AMBER_PREFIX_450 R"GLSL(
21 | layout(location=0) in vec2 position;
22 | layout(location=1) in vec4 color;
23 | layout(location=0) out vec4 vert_color;
24 | void main() {
25 | gl_Position = vec4(position, 0, 1);
26 | vert_color = color;
27 | })GLSL";
28 |
29 | static const std::string fragShaderGLSL = AMBER_PREFIX_450 R"GLSL(
30 | layout(location=0) out vec4 frag_color;
31 | layout(location=0) in vec4 vert_color;
32 | void main() {
33 | frag_color = vert_color;
34 | })GLSL";
35 |
36 | struct Vertex {
37 | float position[2];
38 | uint32_t color;
39 | };
40 |
41 | static const Vertex TRIANGLE_VERTICES[] {
42 | {{1, 0}, 0xffff0000u},
43 | {{cosf(PI * 2 / 3), sinf(PI * 2 / 3)}, 0xff00ff00u},
44 | {{cosf(PI * 4 / 3), sinf(PI * 4 / 3)}, 0xff0000ffu},
45 | };
46 |
47 | int main(const int argc, const char *argv[]) {
48 | // Initialize GLFW and create the window.
49 | glfwInit();
50 | glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
51 | glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
52 | glfwWindowHint(GLFW_DECORATED, GL_FALSE);
53 | glfwWindowHint(GLFW_SAMPLES, 4);
54 | auto* window = glfwCreateWindow(DEMO_WIDTH, DEMO_HEIGHT, "triangle", 0, 0);
55 | glfwSetKeyCallback(window, [] (GLFWwindow* window, int key, int, int action, int) {
56 | if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) {
57 | glfwSetWindowShouldClose(window, GLFW_TRUE);
58 | }
59 | });
60 |
61 | // Create the VkInstance, VkDevice, etc.
62 | LavaContext* context = LavaContext::create({
63 | .depthBuffer = false,
64 | .validation = true,
65 | .samples = VK_SAMPLE_COUNT_1_BIT,
66 | .createSurface = [window] (VkInstance instance) {
67 | VkSurfaceKHR surface;
68 | glfwCreateWindowSurface(instance, window, nullptr, &surface);
69 | return surface;
70 | }
71 | });
72 | const VkDevice device = context->getDevice();
73 | const VkPhysicalDevice gpu = context->getGpu();
74 | const VkRenderPass renderPass = context->getRenderPass();
75 | const VkExtent2D extent = context->getSize();
76 |
77 | // Fill in a shared CPU-GPU vertex buffer.
78 | LavaCpuBuffer* vertexBuffer = LavaCpuBuffer::create({
79 | .device = device,
80 | .gpu = gpu,
81 | .size = sizeof(TRIANGLE_VERTICES),
82 | .source = TRIANGLE_VERTICES,
83 | .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
84 | });
85 |
86 | // Compile shaders.
87 | auto program = AmberProgram::create(vertShaderGLSL, fragShaderGLSL);
88 | program->compile(device);
89 | VkShaderModule vshader = program->getVertexShader();
90 | VkShaderModule fshader = program->getFragmentShader();
91 |
92 | // Create the pipeline.
93 | static_assert(sizeof(Vertex) == 12, "Unexpected vertex size.");
94 | LavaPipeCache* pipelines = LavaPipeCache::create({
95 | .device = device,
96 | .descriptorLayouts = {},
97 | .renderPass = renderPass,
98 | .vshader = vshader,
99 | .fshader = fshader,
100 | .vertex = {
101 | .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
102 | .attributes = { {
103 | .binding = 0u,
104 | .format = VK_FORMAT_R32G32_SFLOAT,
105 | .location = 0u,
106 | .offset = 0u,
107 | }, {
108 | .binding = 0u,
109 | .format = VK_FORMAT_R8G8B8A8_UNORM,
110 | .location = 1u,
111 | .offset = 8u,
112 | } },
113 | .buffers = { {
114 | .binding = 0u,
115 | .stride = 12,
116 | } }
117 | }
118 | });
119 | VkPipeline pipeline = pipelines->getPipeline();
120 |
121 | // Main game loop.
122 | while (!glfwWindowShouldClose(window)) {
123 | glfwPollEvents();
124 |
125 | // Start the command buffer and begin the render pass.
126 | VkCommandBuffer cmdbuffer = context->beginFrame();
127 | const VkClearValue clearValue = { .color.float32 = {0.1, 0.2, 0.4, 1.0} };
128 | const VkRenderPassBeginInfo rpbi {
129 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
130 | .framebuffer = context->getFramebuffer(),
131 | .renderPass = renderPass,
132 | .renderArea.extent = extent,
133 | .pClearValues = &clearValue,
134 | .clearValueCount = 1
135 | };
136 | vkCmdBeginRenderPass(cmdbuffer, &rpbi, VK_SUBPASS_CONTENTS_INLINE);
137 |
138 | VkViewport viewport = { .width = (float) extent.width, .height = (float) extent.height };
139 | vkCmdSetViewport(cmdbuffer, 0, 1, &viewport);
140 |
141 | VkRect2D scissor { .extent = extent };
142 | vkCmdSetScissor(cmdbuffer, 0, 1, &scissor);
143 |
144 | vkCmdBindPipeline(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
145 |
146 | VkBuffer buffer[] = { vertexBuffer->getBuffer() };
147 | VkDeviceSize offsets[] = { 0 };
148 | vkCmdBindVertexBuffers(cmdbuffer, 0, 1, buffer, offsets);
149 |
150 | vkCmdDraw(cmdbuffer, 3, 1, 0, 0);
151 |
152 | // End the render pass, flush the command buffer, and present the backbuffer.
153 | vkCmdEndRenderPass(cmdbuffer);
154 | context->endFrame();
155 | }
156 |
157 | // Wait for the command buffers to finish executing.
158 | context->waitFrame();
159 |
160 | // Cleanup.
161 | delete vertexBuffer;
162 | delete pipelines;
163 | delete program;
164 | delete context;
165 | return 0;
166 | }
167 |
--------------------------------------------------------------------------------
/demos/03_triangle_staged.cpp:
--------------------------------------------------------------------------------
1 | // The MIT License
2 | // Copyright (c) 2018 Philip Rideout
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #include
12 |
13 | #include
14 |
15 | using namespace par;
16 |
17 | static constexpr int DEMO_WIDTH = 512;
18 | static constexpr int DEMO_HEIGHT = 512;
19 | static constexpr float PI = 3.1415926535;
20 |
21 | static const std::string vertShaderGLSL = AMBER_PREFIX_450 R"GLSL(
22 | layout(location=0) in vec2 position;
23 | layout(location=1) in vec4 color;
24 | layout(location=0) out vec4 vert_color;
25 | void main() {
26 | gl_Position = vec4(position, 0, 1);
27 | vert_color = color;
28 | })GLSL";
29 |
30 | static const std::string fragShaderGLSL = AMBER_PREFIX_450 R"GLSL(
31 | layout(location=0) out vec4 frag_color;
32 | layout(location=0) in vec4 vert_color;
33 | void main() {
34 | frag_color = vert_color;;
35 | })GLSL";
36 |
37 | struct Vertex {
38 | float position[2];
39 | uint32_t color;
40 | };
41 |
42 | static const Vertex TRIANGLE_VERTICES[] {
43 | {{1, 0}, 0xffff0000u},
44 | {{cosf(PI * 2 / 3), sinf(PI * 2 / 3)}, 0xff00ff00u},
45 | {{cosf(PI * 4 / 3), sinf(PI * 4 / 3)}, 0xff0000ffu},
46 | };
47 |
48 | int main(const int argc, const char *argv[]) {
49 | // Initialize GLFW and create the window.
50 | glfwInit();
51 | glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
52 | glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
53 | glfwWindowHint(GLFW_DECORATED, GL_FALSE);
54 | glfwWindowHint(GLFW_SAMPLES, 4);
55 | auto* window = glfwCreateWindow(DEMO_WIDTH, DEMO_HEIGHT, "triangle", 0, 0);
56 | glfwSetKeyCallback(window, [] (GLFWwindow* window, int key, int, int action, int) {
57 | if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) {
58 | glfwSetWindowShouldClose(window, GLFW_TRUE);
59 | }
60 | });
61 |
62 | // Create the VkInstance, VkDevice, etc.
63 | LavaContext* context = LavaContext::create({
64 | .depthBuffer = false,
65 | .validation = true,
66 | .createSurface = [window] (VkInstance instance) {
67 | VkSurfaceKHR surface;
68 | glfwCreateWindowSurface(instance, window, nullptr, &surface);
69 | return surface;
70 | }
71 | });
72 | const VkDevice device = context->getDevice();
73 | const VkPhysicalDevice gpu = context->getGpu();
74 | const VkRenderPass renderPass = context->getRenderPass();
75 | const VkExtent2D extent = context->getSize();
76 |
77 | // Fill in a staging area for the vertex buffer.
78 | LavaCpuBuffer* stage = LavaCpuBuffer::create({
79 | .device = device,
80 | .gpu = gpu,
81 | .size = sizeof(TRIANGLE_VERTICES),
82 | .source = TRIANGLE_VERTICES,
83 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
84 | });
85 | LavaGpuBuffer* vertexBuffer = LavaGpuBuffer::create({
86 | .device = device,
87 | .gpu = gpu,
88 | .size = sizeof(TRIANGLE_VERTICES),
89 | .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT
90 | });
91 |
92 | // Copy the contents of the staging area.
93 | VkCommandBuffer cmdbuffer = context->beginWork();
94 | const VkBufferCopy region = { .size = sizeof(TRIANGLE_VERTICES) };
95 | vkCmdCopyBuffer(cmdbuffer, stage->getBuffer(), vertexBuffer->getBuffer(), 1, ®ion);
96 | context->endWork();
97 |
98 | // Compile shaders.
99 | auto program = AmberProgram::create(vertShaderGLSL, fragShaderGLSL);
100 | program->compile(device);
101 | VkShaderModule vshader = program->getVertexShader();
102 | VkShaderModule fshader = program->getFragmentShader();
103 |
104 | // Create the pipeline.
105 | static_assert(sizeof(Vertex) == 12, "Unexpected vertex size.");
106 | LavaPipeCache* pipelines = LavaPipeCache::create({
107 | .device = device,
108 | .descriptorLayouts = {},
109 | .renderPass = renderPass,
110 | .vshader = vshader,
111 | .fshader = fshader,
112 | .vertex = {
113 | .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
114 | .attributes = { {
115 | .binding = 0u,
116 | .format = VK_FORMAT_R32G32_SFLOAT,
117 | .location = 0u,
118 | .offset = 0u,
119 | }, {
120 | .binding = 0u,
121 | .format = VK_FORMAT_R8G8B8A8_UNORM,
122 | .location = 1u,
123 | .offset = 8u,
124 | } },
125 | .buffers = { {
126 | .binding = 0u,
127 | .stride = 12,
128 | } }
129 | }
130 | });
131 | VkPipeline pipeline = pipelines->getPipeline();
132 |
133 | // Ensure the VBO is ready before we start drawing.
134 | context->waitWork();
135 | delete stage;
136 |
137 | // Main game loop.
138 | while (!glfwWindowShouldClose(window)) {
139 | glfwPollEvents();
140 |
141 | // Start the command buffer and begin the render pass.
142 | VkCommandBuffer cmdbuffer = context->beginFrame();
143 | const VkClearValue clearValue = { .color.float32 = {0.1, 0.2, 0.4, 1.0} };
144 | const VkRenderPassBeginInfo rpbi {
145 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
146 | .framebuffer = context->getFramebuffer(),
147 | .renderPass = renderPass,
148 | .renderArea.extent = extent,
149 | .pClearValues = &clearValue,
150 | .clearValueCount = 1
151 | };
152 | vkCmdBeginRenderPass(cmdbuffer, &rpbi, VK_SUBPASS_CONTENTS_INLINE);
153 |
154 | VkViewport viewport = { .width = (float) extent.width, .height = (float) extent.height };
155 | vkCmdSetViewport(cmdbuffer, 0, 1, &viewport);
156 |
157 | VkRect2D scissor { .extent = extent };
158 | vkCmdSetScissor(cmdbuffer, 0, 1, &scissor);
159 |
160 | vkCmdBindPipeline(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
161 |
162 | VkBuffer buffer[] = { vertexBuffer->getBuffer() };
163 | VkDeviceSize offsets[] = { 0 };
164 | vkCmdBindVertexBuffers(cmdbuffer, 0, 1, buffer, offsets);
165 |
166 | vkCmdDraw(cmdbuffer, 3, 1, 0, 0);
167 |
168 | // End the render pass, flush the command buffer, and present the backbuffer.
169 | vkCmdEndRenderPass(cmdbuffer);
170 | context->endFrame();
171 | }
172 |
173 | // Wait for the command buffers to finish executing.
174 | context->waitFrame();
175 |
176 | // Cleanup.
177 | delete vertexBuffer;
178 | delete pipelines;
179 | delete program;
180 | delete context;
181 | return 0;
182 | }
183 |
--------------------------------------------------------------------------------
/demos/04_triangle_recorded.cpp:
--------------------------------------------------------------------------------
1 | // The MIT License
2 | // Copyright (c) 2018 Philip Rideout
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #include
12 |
13 | #include
14 |
15 | namespace {
16 | constexpr int DEMO_WIDTH = 512;
17 | constexpr int DEMO_HEIGHT = 512;
18 | constexpr float PI = 3.1415926535;
19 |
20 | const std::string vertShaderGLSL = AMBER_PREFIX_450 R"GLSL(
21 | layout(location=0) in vec2 position;
22 | layout(location=1) in vec4 color;
23 | layout(location=0) out vec4 vert_color;
24 | void main() {
25 | gl_Position = vec4(position, 0, 1);
26 | vert_color = color;
27 | })GLSL";
28 |
29 | const std::string fragShaderGLSL = AMBER_PREFIX_450 R"GLSL(
30 | layout(location=0) out vec4 frag_color;
31 | layout(location=0) in vec4 vert_color;
32 | void main() {
33 | frag_color = vert_color;
34 | })GLSL";
35 |
36 | struct Vertex {
37 | float position[2];
38 | uint32_t color;
39 | };
40 |
41 | const Vertex TRIANGLE_VERTICES[] {
42 | {{1, 0}, 0xffff0000u},
43 | {{cosf(PI * 2 / 3), sinf(PI * 2 / 3)}, 0xff00ff00u},
44 | {{cosf(PI * 4 / 3), sinf(PI * 4 / 3)}, 0xff0000ffu},
45 | };
46 | }
47 |
48 | int main(const int argc, const char *argv[]) {
49 | // Initialize GLFW and create the window.
50 | GLFWwindow* window;
51 | {
52 | glfwInit();
53 | glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
54 | glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
55 | glfwWindowHint(GLFW_DECORATED, GL_FALSE);
56 | glfwWindowHint(GLFW_SAMPLES, 4);
57 | window = glfwCreateWindow(DEMO_WIDTH, DEMO_HEIGHT, "triangle", 0, 0);
58 | glfwSetKeyCallback(window, [] (GLFWwindow* window, int key, int, int action, int) {
59 | if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) {
60 | glfwSetWindowShouldClose(window, GLFW_TRUE);
61 | }
62 | });
63 | }
64 |
65 | // Create the VkInstance, VkDevice, etc.
66 | using namespace par;
67 | LavaContext* context = LavaContext::create({
68 | .depthBuffer = false,
69 | .validation = true,
70 | .samples = VK_SAMPLE_COUNT_1_BIT,
71 | .createSurface = [window] (VkInstance instance) {
72 | VkSurfaceKHR surface;
73 | glfwCreateWindowSurface(instance, window, nullptr, &surface);
74 | return surface;
75 | }
76 | });
77 | const VkDevice device = context->getDevice();
78 | const VkPhysicalDevice gpu = context->getGpu();
79 | const VkRenderPass renderPass = context->getRenderPass();
80 | const VkExtent2D extent = context->getSize();
81 |
82 | // Populate a vertex buffer.
83 | LavaGpuBuffer* vertexBuffer;
84 | LavaCpuBuffer* stage;
85 | {
86 | vertexBuffer = LavaGpuBuffer::create({
87 | .device = device,
88 | .gpu = gpu,
89 | .size = sizeof(TRIANGLE_VERTICES),
90 | .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT
91 | });
92 | stage = LavaCpuBuffer::create({
93 | .device = device,
94 | .gpu = gpu,
95 | .size = sizeof(TRIANGLE_VERTICES),
96 | .source = TRIANGLE_VERTICES,
97 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
98 | });
99 | VkCommandBuffer cmdbuffer = context->beginWork();
100 | const VkBufferCopy region = { .size = sizeof(TRIANGLE_VERTICES) };
101 | vkCmdCopyBuffer(cmdbuffer, stage->getBuffer(), vertexBuffer->getBuffer(), 1, ®ion);
102 | context->endWork();
103 | }
104 |
105 | // Compile shaders.
106 | auto program = AmberProgram::create(vertShaderGLSL, fragShaderGLSL);
107 | program->compile(device);
108 | VkShaderModule vshader = program->getVertexShader();
109 | VkShaderModule fshader = program->getFragmentShader();
110 |
111 | // Create the pipeline.
112 | static_assert(sizeof(Vertex) == 12, "Unexpected vertex size.");
113 | LavaPipeCache* pipelines = LavaPipeCache::create({
114 | .device = device,
115 | .descriptorLayouts = {},
116 | .renderPass = renderPass,
117 | .vshader = vshader,
118 | .fshader = fshader,
119 | .vertex = {
120 | .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
121 | .attributes = { {
122 | .binding = 0u,
123 | .format = VK_FORMAT_R32G32_SFLOAT,
124 | .location = 0u,
125 | .offset = 0u,
126 | }, {
127 | .binding = 0u,
128 | .format = VK_FORMAT_R8G8B8A8_UNORM,
129 | .location = 1u,
130 | .offset = 8u,
131 | } },
132 | .buffers = { {
133 | .binding = 0u,
134 | .stride = 12,
135 | } }
136 | }
137 | });
138 | VkPipeline pipeline = pipelines->getPipeline();
139 |
140 | // Ensure the VBO is ready before we start drawing.
141 | context->waitWork();
142 | delete stage;
143 |
144 | // Record two command buffers.
145 | LavaRecording* frame = context->createRecording();
146 | for (uint32_t i = 0; i < 2; i++) {
147 | const VkCommandBuffer cmdbuffer = context->beginRecording(frame, i);
148 | const VkClearValue clearValue = { .color.float32 = {0.1, 0.2, 0.4, 1.0} };
149 | const VkRenderPassBeginInfo rpbi {
150 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
151 | .framebuffer = context->getFramebuffer(i),
152 | .renderPass = renderPass,
153 | .renderArea.extent = extent,
154 | .pClearValues = &clearValue,
155 | .clearValueCount = 1
156 | };
157 | const VkViewport viewport = {
158 | .width = (float) extent.width,
159 | .height = (float) extent.height
160 | };
161 | const VkRect2D scissor { .extent = extent };
162 | const VkBuffer buffer[] = { vertexBuffer->getBuffer() };
163 | const VkDeviceSize offsets[] = { 0 };
164 | vkCmdBeginRenderPass(cmdbuffer, &rpbi, VK_SUBPASS_CONTENTS_INLINE);
165 | vkCmdSetViewport(cmdbuffer, 0, 1, &viewport);
166 | vkCmdSetScissor(cmdbuffer, 0, 1, &scissor);
167 | vkCmdBindPipeline(cmdbuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
168 | vkCmdBindVertexBuffers(cmdbuffer, 0, 1, buffer, offsets);
169 | vkCmdDraw(cmdbuffer, 3, 1, 0, 0);
170 | vkCmdEndRenderPass(cmdbuffer);
171 | context->endRecording();
172 | }
173 |
174 | // Main game loop.
175 | while (!glfwWindowShouldClose(window)) {
176 | glfwPollEvents();
177 | context->presentRecording(frame);
178 | }
179 |
180 | // Wait for the command buffer to finish executing.
181 | context->waitRecording(frame);
182 |
183 | // Cleanup.
184 | context->freeRecording(frame);
185 | delete vertexBuffer;
186 | delete pipelines;
187 | delete program;
188 | delete context;
189 | return 0;
190 | }
191 |
--------------------------------------------------------------------------------
/demos/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.6)
2 |
3 | project(LavaDemos)
4 |
5 | set(AMBER_SOURCE
6 | ../src/AmberCompiler.cpp
7 | ../src/AmberProgram.cpp)
8 |
9 | set(DEMO_LIBS glfw glslang SPIRV curl sfw_lib lava)
10 |
11 | if(APPLE)
12 | if($ENV{VULKAN_SDK})
13 | list(APPEND DEMO_LIBS "$ENV{VULKAN_SDK}/macOS/lib/libvulkan.1.dylib")
14 | endif()
15 | endif()
16 |
17 | link_libraries(${DEMO_LIBS})
18 |
19 | include_directories(
20 | ../extras
21 | ../extras/glslang
22 | ../extras/par
23 | ../extras/stb
24 | ../extras/tinyobjloader
25 | ../extras/SimpleFileWatcher/include
26 | ../include)
27 |
28 | set(DEMO_NAMES
29 | 01_clear_screen
30 | 02_triangle_shared
31 | 03_triangle_staged
32 | 04_triangle_recorded
33 | 05_spinny_double
34 | 06_spinny_staged
35 | 07_hello_texture
36 | 08_klein_bottle
37 | 09_particle_system
38 | 0a_particle_system)
39 |
40 | # Build the Desktop-only GLFW demos.
41 |
42 | foreach(DEMO ${DEMO_NAMES})
43 | add_executable(${DEMO} ${DEMO}.cpp ${AMBER_SOURCE})
44 | set_target_properties(${DEMO} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
45 | endforeach()
46 |
47 | ## Build Mobile-friendly Amber demos.
48 |
49 | set(AMBER_DEMOS
50 | 0b_shadertoy
51 | 0c_framebuffer)
52 |
53 | foreach(DEMO ${AMBER_DEMOS})
54 | add_executable(${DEMO} ${DEMO}.cpp ${AMBER_SOURCE} ../src/AmberMain.cpp)
55 | set_target_properties(${DEMO} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
56 | endforeach()
57 |
--------------------------------------------------------------------------------
/demos/README.md:
--------------------------------------------------------------------------------
1 | This folder contains a series of simple independent Lava demos that use
2 | [GLFW](https://github.com/glfw/glfw) for windowing and
3 | [glslang](https://github.com/KhronosGroup/glslang) for real-time SPIRV generation.
4 |
5 | Note that the core Lava library does not have dependencies on GLFW or glslang. **AmberProgram** and
6 | **AmberCompiler** depend on glslang but they live outside the core Lava library.
7 |
8 | | Demo | Description |
9 | |------|--------------|
10 | | [clear_screen](01_clear_screen.cpp) | Simplest demo and does not draw any geometry.
11 | | [triangle_shared](02_triangle_shared.cpp) | Draws a triangle using a vertex buffer that resides in shared CPU-GPU memory.
12 | | [triangle_staged](03_triangle_staged.cpp) | Draws a triangle using a vertex buffer uploaded from a staging area.
13 | | [triangle_recorded](04_triangle_recorded.cpp) | Draws a triangle using a recorded command buffer.
14 | | [klein_bottle](08_klein_bottle.cpp) | Indexed triangles with a depth buffer and MSAA.
15 | | [particle_system](0a_particle_system.cpp) | Fun with point sprites.
16 | | [shadertoy](0b_shadertoy.cpp) | Full screen triangle with a complex fragment shader.
17 | | [framebuffer](0c_framebuffer.cpp) | Offscreen framebuffer.
18 |
--------------------------------------------------------------------------------
/docs/apidoc.css:
--------------------------------------------------------------------------------
1 | body {
2 | max-width: 50em;
3 | font-size: 16px;
4 | line-height: 1.6;
5 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
6 | text-align: left;
7 | margin: 1.5em;
8 | padding: 0 1em;
9 | }
10 |
11 | .md ul:first-of-type {
12 | list-style-type: none;
13 | padding-left:0;
14 | }
15 |
16 | span > ul > li > a:first-of-type {
17 | font-weight: bold;
18 | }
19 |
20 | .md ul:first-of-type em.asterisk {
21 | font-weight: 300;
22 | font-style: normal;
23 | color: gray;
24 | }
25 |
26 | .md ul:first-of-type li li {
27 | list-style-type: none;
28 | padding-left: 30px;
29 | }
30 |
31 | .md .gotop {
32 | font-weight: normal;
33 | font-size: 10px;
34 | float: right;
35 | color: #99a3d8 !important;
36 | }
37 |
38 | .md h2 .gotop, .md h3 .gotop {
39 | line-height: 50px;
40 | }
41 |
42 | .md h4 .gotop {
43 | line-height: 40px;
44 | }
45 |
46 | .md a,
47 | .md div.title, contents, .md .tocHeader,
48 | .md h1, .md h2, .md h3, .md h4, .md h5, .md h6,
49 | .md .nonumberh1, .md .nonumberh2, .md .nonumberh3, .md .nonumberh4, .md .nonumberh5, .md .nonumberh6,
50 | .md .shortTOC, .md .mediumTOC, .md .longTOC {
51 | font-family: inherit;
52 | }
53 |
54 | .md div.title {
55 | margin: 0.4em 0 0 0;
56 | padding: 0;
57 | text-align: inherit;
58 | /* font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif; */
59 | color: #cc8400 !important;
60 | }
61 |
62 | .md div.subtitle {
63 | text-align: inherit;
64 | }
65 |
66 | /* faint border below headings */
67 | .md h1, .md h2, .md h3, .md h4,
68 | .md .nonumberh1, .md .nonumberh2, .md .nonumberh3, .md .nonumberh4 {
69 | border-bottom: 1px solid rgba(0,0,0,.1);
70 | }
71 | /* heading font styles */
72 | .md h1, .md .nonumberh1, .md div.title {
73 | font-size: 150%;
74 | font-weight: 600;
75 | color: rgba(0,0,0,.7);
76 | }
77 | .md h2, .md .nonumberh2 {
78 | font-size: 120%;
79 | font-weight: 400;
80 | color: rgba(0,0,0,.9);
81 | }
82 | .md h3, .md .nonumberh3 {
83 | font-size: 110%;
84 | font-weight: 400;
85 | color: rgba(0,0,0,.7);
86 | }
87 | /* no numbering of headings */
88 | .md h1:before, .md h2:before, .md h3:before, .md h4:before { content: none; }
89 |
90 | /* link styling */
91 | .md a:link, .md a:visited {
92 | color: #3f51b5;
93 | }
94 |
95 | /* inline and block code */
96 | .md code, .md pre.listing {
97 | background-color: rgba(0,0,0,.05);
98 | padding: 0.1em 0.2em;
99 | border-radius: 0.15em;
100 | }
101 | .md pre.listing code {
102 | background-color: transparent;
103 | padding: 0;
104 | border: none;
105 | }
106 |
107 | img:first-of-type {
108 | height: 128px;
109 | border-radius: 10px;
110 | }
--------------------------------------------------------------------------------
/extras/android/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | .externalNativeBuild
3 | app/build
4 | .gradle
--------------------------------------------------------------------------------
/extras/android/README.md:
--------------------------------------------------------------------------------
1 | First, verify that you have Vulkan libs available in your NDK:
2 |
3 | ```
4 | find ${ANDROID_HOME}/ndk-bundle -name vulkan*.h
5 | find ${ANDROID_HOME}/ndk-bundle -name libvulkan.so
6 | ```
7 |
8 | To build:
9 |
10 | ```
11 | cd lava/extras/android
12 | ./gradlew build
13 | ```
14 |
15 | To verify:
16 | ```
17 | ls -l app/build/outputs/apk/debug/app-debug.apk
18 | jar -tvf app/build/outputs/apk/debug/app-debug.apk | grep .so$
19 | jar -tvf app/build/outputs/apk/release/app-release-unsigned.apk | grep .so$
20 | ```
21 |
22 | To install, wake device, and launch:
23 | ```
24 | adb install -r app/build/outputs/apk/debug/app-debug.apk
25 | adb shell input keyevent 26 ; adb shell input keyevent 82
26 | adb logcat -c ; adb shell am start -n net.prideout.lava.lavademo/android.app.NativeActivity
27 | ```
28 |
29 | To dump the logs:
30 | ```
31 | export PID=`adb shell ps | grep net.prideout.lava.lavademo | tr -s [:space:] ' ' | cut -d' ' -f2`
32 | adb logcat | grep -F $PID
33 | ```
34 |
35 | To clobber:
36 | ```
37 | rm -rf build app/build app/.externalNativeBuild
38 | ```
39 |
40 | To uninstall:
41 | ```
42 | adb uninstall net.prideout.lava.lavademo
43 | ```
44 |
--------------------------------------------------------------------------------
/extras/android/app/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.4.1)
2 |
3 | if (${ANDROID_ABI} STREQUAL "x86_64")
4 | include_directories(${ANDROID_SYSROOT}/usr/include/x86_64-linux-android)
5 | elseif (${ANDROID_ABI} STREQUAL "x86")
6 | include_directories(${ANDROID_SYSROOT}/usr/include/i686-linux-android)
7 | elseif (${ANDROID_ABI} STREQUAL "arm64-v8a")
8 | include_directories(${ANDROID_SYSROOT}/usr/include/aarch64-linux-android)
9 | elseif (${ANDROID_ABI} STREQUAL "armeabi-v7a")
10 | include_directories(${ANDROID_SYSROOT}/usr/include/arm-linux-androideabi)
11 | endif()
12 |
13 | set(APP_GLUE_DIR ${ANDROID_NDK}/sources/android/native_app_glue)
14 | include_directories(${APP_GLUE_DIR})
15 | set(CMAKE_CXX_FLAGS "-std=c++14 -stdlib=libc++ -fno-rtti")
16 |
17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_ANDROID_KHR")
18 | add_library(appglue STATIC ${APP_GLUE_DIR}/android_native_app_glue.c)
19 |
20 | add_subdirectory(lava)
21 | add_subdirectory(lava/extras/glslang)
22 |
23 | include_directories(
24 | lava/extras
25 | lava/extras/glslang
26 | lava/extras/par
27 | lava/extras/stb
28 | lava/extras/tinyobjloader
29 | lava/include)
30 |
31 | add_library(lavademos SHARED
32 | lava/src/AmberMain.cpp
33 | lava/src/AmberProgram.cpp
34 | lava/src/AmberCompiler.cpp
35 | src/main/cpp/ClearScreenApp.cpp
36 | src/main/cpp/TriangleRecordedApp.cpp)
37 |
38 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")
39 | target_link_libraries(lavademos log android appglue lava glslang SPIRV)
40 |
--------------------------------------------------------------------------------
/extras/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | applicationId "net.prideout.lava.lavademo"
7 | minSdkVersion 27
8 | targetSdkVersion 28
9 | versionCode 1
10 | versionName "1.0"
11 | externalNativeBuild {
12 | cmake {
13 | cppFlags "-std=c++14"
14 | }
15 | }
16 | }
17 | externalNativeBuild {
18 | cmake {
19 | path "CMakeLists.txt"
20 | }
21 | }
22 | sourceSets {
23 | debug {
24 | jniLibs {
25 | srcDirs = ["${android.ndkDirectory}/sources/third_party/vulkan/src/build-android/jniLibs"]
26 | }
27 | }
28 | }
29 | }
30 |
31 | dependencies {
32 | implementation fileTree(dir: 'libs', include: ['*.jar'])
33 | }
34 |
--------------------------------------------------------------------------------
/extras/android/app/lava:
--------------------------------------------------------------------------------
1 | ../../..
--------------------------------------------------------------------------------
/extras/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/extras/android/app/src/main/cpp/ClearScreenApp.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include
6 |
7 | using namespace std;
8 | using namespace par;
9 |
10 | struct ClearScreenApp : AmberApplication {
11 | ClearScreenApp(SurfaceFn createSurface);
12 | ~ClearScreenApp();
13 | void draw(double seconds) override;
14 | LavaContext* mContext = nullptr;
15 | };
16 |
17 | ClearScreenApp::ClearScreenApp(SurfaceFn createSurface) {
18 | mContext = LavaContext::create({
19 | .depthBuffer = false,
20 | .validation = true,
21 | .samples = VK_SAMPLE_COUNT_1_BIT,
22 | .createSurface = createSurface
23 | });
24 | llog.info("LavaContext created.");
25 | }
26 |
27 | ClearScreenApp::~ClearScreenApp() {
28 | delete mContext;
29 | }
30 |
31 | void ClearScreenApp::draw(double seconds) {
32 | VkCommandBuffer cmdbuffer = mContext->beginFrame();
33 | const float red = fmod(seconds, 1.0);
34 | const VkClearValue clearValue = { .color.float32 = {red, 0, 0, 1} };
35 | const VkRenderPassBeginInfo rpbi {
36 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
37 | .framebuffer = mContext->getFramebuffer(),
38 | .renderPass = mContext->getRenderPass(),
39 | .renderArea.extent.width = mContext->getSize().width,
40 | .renderArea.extent.height = mContext->getSize().height,
41 | .pClearValues = &clearValue,
42 | .clearValueCount = 1
43 | };
44 | vkCmdBeginRenderPass(cmdbuffer, &rpbi, VK_SUBPASS_CONTENTS_INLINE);
45 |
46 | // ...do not draw any geometry...
47 |
48 | // End the render pass, flush the command buffer, and present the backbuffer.
49 | vkCmdEndRenderPass(cmdbuffer);
50 | mContext->endFrame();
51 | }
52 |
53 | static AmberApplication::Register app("clearscreen", [] (AmberApplication::SurfaceFn cb) {
54 | return new ClearScreenApp(cb);
55 | });
56 |
--------------------------------------------------------------------------------
/extras/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | LavaDemo
3 |
4 |
--------------------------------------------------------------------------------
/extras/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.1.3'
11 |
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/extras/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
--------------------------------------------------------------------------------
/extras/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prideout/lava/57764f7945a18be3b4ab12b50004c4266fd464ac/extras/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/extras/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Jun 27 10:50:24 PDT 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-all.zip
7 |
--------------------------------------------------------------------------------
/extras/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/extras/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/extras/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/extras/assets/abstract.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prideout/lava/57764f7945a18be3b4ab12b50004c4266fd464ac/extras/assets/abstract.jpg
--------------------------------------------------------------------------------
/extras/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prideout/lava/57764f7945a18be3b4ab12b50004c4266fd464ac/extras/assets/icon.png
--------------------------------------------------------------------------------
/extras/assets/klein.glsl:
--------------------------------------------------------------------------------
1 |
2 | // @program p_texture, klein.vertex, texture
3 | // @program p_cylinder, klein.vertex, cylinder.fragment
4 | // @program p_podium, klein.vertex, podium.fragment
5 | // @program p_logo, logo.vertex, texture
6 |
7 | uniform mat4 u_mvp;
8 | uniform sampler2D u_ao;
9 | uniform sampler2D u_rust;
10 | uniform sampler2D u_reflection;
11 | uniform vec2 u_resolution;
12 | varying vec2 v_texcoord;
13 | varying vec3 v_position;
14 |
15 | -- klein.vertex
16 |
17 | attribute vec4 a_position;
18 | attribute vec2 a_texcoord;
19 |
20 | void main()
21 | {
22 | gl_Position = u_mvp * a_position;
23 | v_texcoord = a_texcoord;
24 | v_position = a_position.xyz;
25 | }
26 |
27 | -- logo.vertex
28 |
29 | attribute vec4 a_position;
30 | attribute vec2 a_texcoord;
31 |
32 | void main()
33 | {
34 | gl_Position = a_position;
35 | gl_Position.xy *= 0.4;
36 | gl_Position.xy += 0.7;
37 | v_texcoord = a_texcoord + 0.5;
38 | }
39 |
40 | -- texture
41 |
42 | void main()
43 | {
44 | gl_FragColor = texture2D(u_ao, v_texcoord);
45 | }
46 |
47 | -- cylinder.fragment
48 |
49 | void main()
50 | {
51 | gl_FragColor = vec4(0.56, 0.31, 0.17, 1.0);
52 | }
53 |
54 | -- podium.fragment
55 |
56 | void main()
57 | {
58 | gl_FragColor = texture2D(u_ao, v_texcoord);
59 | gl_FragColor *= texture2D(u_rust, v_position.xz);
60 | vec4 reflection = texture2D(u_reflection, gl_FragCoord.xy / u_resolution);
61 | reflection.a *= gl_FragCoord.z;
62 | gl_FragColor.rgb = mix(gl_FragColor.rgb, reflection.rgb, reflection.a);
63 | }
64 |
--------------------------------------------------------------------------------
/extras/assets/klein31416.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prideout/lava/57764f7945a18be3b4ab12b50004c4266fd464ac/extras/assets/klein31416.gif
--------------------------------------------------------------------------------
/extras/assets/particles1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prideout/lava/57764f7945a18be3b4ab12b50004c4266fd464ac/extras/assets/particles1.png
--------------------------------------------------------------------------------
/extras/assets/particles2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prideout/lava/57764f7945a18be3b4ab12b50004c4266fd464ac/extras/assets/particles2.jpg
--------------------------------------------------------------------------------
/extras/assets/particles3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prideout/lava/57764f7945a18be3b4ab12b50004c4266fd464ac/extras/assets/particles3.jpg
--------------------------------------------------------------------------------
/extras/assets/rust.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prideout/lava/57764f7945a18be3b4ab12b50004c4266fd464ac/extras/assets/rust.png
--------------------------------------------------------------------------------
/extras/assets/triptych.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prideout/lava/57764f7945a18be3b4ab12b50004c4266fd464ac/extras/assets/triptych.png
--------------------------------------------------------------------------------
/extras/macos/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.9.0)
2 | project(lavamac)
3 |
4 | set(CMAKE_CXX_FLAGS "-std=c++14 -stdlib=libc++ -fno-rtti")
5 |
6 | set(AMBER_REQUIRED True)
7 | add_definitions(
8 | -DAMBER_COCOA
9 | -DVK_USE_PLATFORM_MACOS_MVK)
10 |
11 | add_subdirectory(lava)
12 | add_subdirectory(lava/extras/glslang)
13 |
14 | include_directories(
15 | lava/extras
16 | lava/extras/glslang
17 | lava/extras/par
18 | lava/extras/stb
19 | lava/extras/tinyobjloader
20 | lava/include)
21 |
22 | add_executable(
23 | lavamac
24 | MACOSX_BUNDLE
25 | ${AMBER_SOURCE}
26 | src/AppDelegate.mm
27 | src/GameViewController.mm
28 | src/main.mm
29 | src/test.cpp
30 | src/AppDelegate.h
31 | src/GameViewController.h
32 | src/SharedStructures.h
33 | src/Shaders.metal
34 | src/MainMenu.xib)
35 |
36 | set_source_files_properties(
37 | src/MainMenu.xib
38 | src/Shaders.metal
39 | PROPERTIES
40 | MACOSX_PACKAGE_LOCATION
41 | Resources)
42 |
43 | set_target_properties(
44 | lavamac
45 | PROPERTIES
46 | MACOSX_BUNDLE_INFO_PLIST
47 | ${CMAKE_CURRENT_LIST_DIR}/src/plist.in)
48 |
49 | target_link_libraries(lavamac
50 | "-framework AppKit"
51 | "-framework Metal"
52 | "-framework MetalKit"
53 | "-framework ModelIO"
54 | lava
55 | glslang
56 | SPIRV)
57 |
58 | if($ENV{VULKAN_SDK})
59 | target_link_libraries(lavamac "$ENV{VULKAN_SDK}/macOS/lib/libvulkan.1.dylib")
60 | else()
61 | # TODO: build a library for CI purposes...
62 | endif()
63 |
--------------------------------------------------------------------------------
/extras/macos/README.md:
--------------------------------------------------------------------------------
1 | *work in progress*
2 |
3 | Building Lava in the usual way (as described
4 | [here](https://prideout.net/lava/#buildingandrunningthedemos)) will create
5 | executables that can run on macOS, but does not create actual app bundles that can be installed
6 | on anybody's machine.
7 |
8 | This folder exists solely to allow creation of macOS app bundles. Using this is optional.
9 |
10 | ```bash
11 | > git clone --recurse-submodules https://github.com/prideout/lava.git
12 | > cd extras/macos
13 | > cmake -H. -B.debug -GXcode # create Xcode project
14 | > cmake --build .debug # build Xcode project
15 | > open .debug/Debug/lavamac.app # launch the app
16 | ```
17 |
--------------------------------------------------------------------------------
/extras/macos/aliases.sh:
--------------------------------------------------------------------------------
1 | alias init="cmake -H. -B.debug -GXcode"
2 | alias build="cmake --build .debug"
3 | alias run="open .debug/Debug/lavamac.app"
4 | alias debug="lldb .debug/Debug/lavamac.app/Contents/MacOS/lavamac -o run"
5 |
--------------------------------------------------------------------------------
/extras/macos/lava:
--------------------------------------------------------------------------------
1 | ../..
--------------------------------------------------------------------------------
/extras/macos/src/AppDelegate.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @interface AppDelegate : NSObject
4 |
5 | @property (assign, nonatomic) IBOutlet NSWindow *window;
6 |
7 | @end
8 |
--------------------------------------------------------------------------------
/extras/macos/src/AppDelegate.mm:
--------------------------------------------------------------------------------
1 | #import "AppDelegate.h"
2 |
3 | @implementation AppDelegate
4 |
5 | @synthesize window = _windows;
6 |
7 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
8 | // Insert code here to initialize your application
9 | }
10 |
11 | @end
12 |
--------------------------------------------------------------------------------
/extras/macos/src/GameViewController.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | @interface GameViewController : NSViewController
5 | @end
6 |
--------------------------------------------------------------------------------
/extras/macos/src/Shaders.metal:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "SharedStructures.h"
4 |
5 | using namespace metal;
6 |
7 | // Variables in constant address space
8 | constant float3 light_position = float3(0.0, 1.0, -1.0);
9 | constant float4 ambient_color = float4(0.18, 0.24, 0.8, 1.0);
10 | constant float4 diffuse_color = float4(0.4, 0.4, 1.0, 1.0);
11 |
12 | typedef struct
13 | {
14 | float3 position [[attribute(0)]];
15 | float3 normal [[attribute(1)]];
16 | } vertex_t;
17 |
18 | typedef struct {
19 | float4 position [[position]];
20 | half4 color;
21 | } ColorInOut;
22 |
23 | // Vertex shader function
24 | vertex ColorInOut lighting_vertex(vertex_t vertex_array [[stage_in]],
25 | constant uniforms_t& uniforms [[ buffer(1) ]])
26 | {
27 | ColorInOut out;
28 |
29 | float4 in_position = float4(vertex_array.position, 1.0);
30 | out.position = uniforms.modelview_projection_matrix * in_position;
31 |
32 | float4 eye_normal = normalize(uniforms.normal_matrix * float4(vertex_array.normal, 0.0));
33 | float n_dot_l = dot(eye_normal.rgb, normalize(light_position));
34 | n_dot_l = fmax(0.0, n_dot_l);
35 |
36 | out.color = half4(ambient_color + diffuse_color * n_dot_l);
37 | return out;
38 | }
39 |
40 | // Fragment shader function
41 | fragment half4 lighting_fragment(ColorInOut in [[stage_in]])
42 | {
43 | return in.color;
44 | }
45 |
--------------------------------------------------------------------------------
/extras/macos/src/SharedStructures.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | typedef struct __attribute__((__aligned__(256)))
6 | {
7 | matrix_float4x4 modelview_projection_matrix;
8 | matrix_float4x4 normal_matrix;
9 | } uniforms_t;
10 |
--------------------------------------------------------------------------------
/extras/macos/src/main.mm:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | int main(int argc, const char *argv[]) {
4 | return NSApplicationMain(argc, argv);
5 | }
6 |
--------------------------------------------------------------------------------
/extras/macos/src/plist.in:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 | CFBundleDevelopmentRegion
11 | en
12 | CFBundleDisplayName
13 | ${PRODUCT_NAME}
14 | CFBundleExecutable
15 | ${MACOSX_BUNDLE_EXECUTABLE_NAME}
16 | CFBundleGetInfoString
17 | ${MACOSX_BUNDLE_INFO_STRING}
18 | CFBundleIconFile
19 | ${MACOSX_BUNDLE_ICON_FILE}
20 | CFBundleIdentifier
21 | ${MACOSX_BUNDLE_GUI_IDENTIFIER}
22 | CFBundleInfoDictionaryVersion
23 | 6.0
24 | CFBundleLongVersionString
25 | ${MACOSX_BUNDLE_LONG_VERSION_STRING}
26 | CFBundleName
27 | ${MACOSX_BUNDLE_BUNDLE_NAME}
28 | CFBundlePackageType
29 | APPL
30 | CFBundleShortVersionString
31 | ${MACOSX_BUNDLE_SHORT_VERSION_STRING}
32 | CFBundleSignature
33 | ????
34 | CFBundleVersion
35 | ${MACOSX_BUNDLE_BUNDLE_VERSION}
36 | CSResourcesFileMapped
37 |
38 | NSHumanReadableCopyright
39 | ${MACOSX_BUNDLE_COPYRIGHT}
40 | LSMinimumSystemVersion
41 | ${MACOSX_DEPLOYMENT_TARGET}
42 | NSMainNibFile
43 | MainMenu
44 | NSPrincipalClass
45 | NSApplication
46 |
47 |
48 |
--------------------------------------------------------------------------------
/extras/todo.md:
--------------------------------------------------------------------------------
1 | # DescCache needs a reset method for when you swap over to a new command buffer.
2 |
3 | # Add a test similar to 00_destroy from the moltenvk branch
4 |
5 | # See recent DescCache fixes; do we need these for other Caches?
6 |
7 | # SurfCache should take usage flags instead of enableRead / enableUpload
8 |
9 | # SurfCache should provide a transition cmd for the stuff at the end of streamlines draw function
10 |
11 | # GPU selector
12 |
13 | GPU selector command line argument (integer) and LavaContext config
14 |
15 | # MacOS Bundles
16 |
17 | extra/macos
18 | GameController needs to be fleshed out similar to AmberMain
19 |
20 | # Android
21 |
22 | HelloTexture
23 |
24 | # AmberApplication, AmberMain
25 |
26 | Refactor all or some non-android demos (keep their file names though)
27 |
28 | # LavaCpuBuffer
29 |
30 | remove setData in favor of persistent mapping
31 |
32 | # LavaGeometry
33 |
34 | Test with 08_klein_bottle
35 | Only supports two "attribs" because it assumes non-position data is interleaved
36 |
37 | # Android Swipe
38 |
39 | Navigate between demos, with a hardcoded starting app.
40 |
41 | # gli and ktx pipeline
42 |
43 | cdwfs/img2ktx
44 |
45 | # .clang-format
46 |
47 | .clang-format
48 | AlignAfterOpenBracket: BAS_DontAlign
49 |
50 | # Add testing matrix to README.md
51 |
52 | ------------
53 | | Andrid Studio Version | cmake in SDK| NDK | device |
54 | |-----------------------|-------------|----------|---------|
55 | | 3.0.0 | 3.6.4111459 | NDK-r16 | Pixel XL|
56 |
57 | # lavaray
58 |
59 | Lava as a submodule
60 | RadeonRays as a submodule, in OpenCL mode for now.
61 | Emulate their cornell box example (non shadowed)
62 | Emulate their shadowed cornell box example (including OpenGL kernel)
63 |
64 | # LavaTexture
65 |
66 | Add miplevel support, test with stb_image_resize
67 |
68 | # Texture space caching
69 |
70 | https://software.intel.com/sites/default/files/managed/b4/a0/author_preprint_texture-space-caching-and-reconstruction-for-ray-tracing.pdf
71 |
72 | # Demo ideas
73 |
74 | streamlines https://www.kovach.me/posts/2018-04-30-blotch.html
75 | space_colony https://twitter.com/BendotK/status/1005209740874584064
76 | http://algorithmicbotany.org/papers/colonization.egwnp2007.large.pdf
77 | http://algorithmicbotany.org/papers/venation.sig2005.pdf
78 | demos/circle draws filled-in circle with random sampling
79 | demos/gamma https://www.shadertoy.com/view/llBGz1
80 | demos/smallpt https://www.codeplay.com/portal/sycl-ing-the-smallpt-raytracer
81 | demos/sdfshapes https://www.shadertoy.com/view/4dfXDn
82 | demos/skinning Cesium Skinning and glTF and rapidjson
83 | https://github.com/prideout/recipes
84 | http://xeogl.org/examples/#materials_metallic_fireHydrant
85 | https://github.com/syoyo/tinygltf
86 |
87 | # Path tracer notes
88 |
89 | https://developer.apple.com/documentation/metalperformanceshaders/metal_for_accelerating_ray_tracing
90 | https://github.com/prideout/aobaker
91 | https://github.com/RobotLocomotion/homebrew-director/blob/master/Formula/embree.rb
92 | https://embree.github.io/data/embree-siggraph-2017-final.pdf
93 | https://github.com/aras-p/ToyPathTracer
94 | https://github.com/lighttransport/nanort
95 | http://aantron.github.io/better-enums/ (overkill)
96 | https://www.cgbookcase.com/downloads/
97 | http://graphics.stanford.edu/~henrik/images/cbox.html (best cornell box)
98 | https://github.com/SaschaWillems/Vulkan/blob/master/examples/raytracing/raytracing.cpp
99 | https://github.com/GoGreenOrDieTryin/Vulkan-GPU-Ray-Tracer
100 | http://www.kevinbeason.com/smallpt/
101 | https://github.com/munificent/smallpt/blob/master/smallpt.cpp
102 | http://www.hxa.name/minilight/
103 |
--------------------------------------------------------------------------------
/extras/vscode/c_cpp_properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "configurations": [
3 | {
4 | "name": "Mac",
5 | "browse": {
6 | "path": [
7 | "${workspaceFolder}"
8 | ],
9 | "limitSymbolsToIncludedHeaders": true
10 | },
11 | "includePath": [
12 | "${workspaceFolder}/include",
13 | "${workspaceFolder}/extras/glfw/include",
14 | "${workspaceFolder}/extras/SimpleFileWatcher/include",
15 | "${workspaceFolder}/extras",
16 | "${workspaceFolder}/extras/stb",
17 | "${workspaceFolder}/extras/par",
18 | "${workspaceFolder}/extras/tinyobjloader",
19 | "${workspaceFolder}/extras/glslang",
20 | "${ANDROID_HOME}/ndk-bundle/sources/android/native_app_glue",
21 | "${ANDROID_HOME}/ndk-bundle/sysroot/usr/include",
22 | "${ANDROID_HOME}/ndk-bundle/sysroot/usr/include/arm-linux-androideabi"
23 | ],
24 | "defines": [],
25 | "macFrameworkPath": [
26 | "/System/Library/Frameworks",
27 | "/Library/Frameworks"
28 | ],
29 | "compilerPath": "/usr/bin/clang",
30 | "cStandard": "c11",
31 | "cppStandard": "c++17",
32 | "intelliSenseMode": "clang-x64"
33 | }
34 | ],
35 | "version": 4
36 | }
--------------------------------------------------------------------------------
/extras/vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.defaultLanguage": "cpp",
3 | "files.associations": {
4 | "*.html": "markdown",
5 | "__bit_reference": "cpp",
6 | "__functional_base": "cpp",
7 | "atomic": "cpp",
8 | "bitset": "cpp",
9 | "chrono": "cpp",
10 | "functional": "cpp",
11 | "iterator": "cpp",
12 | "limits": "cpp",
13 | "memory": "cpp",
14 | "ratio": "cpp",
15 | "system_error": "cpp",
16 | "tuple": "cpp",
17 | "type_traits": "cpp",
18 | "vector": "cpp",
19 | "__config": "cpp",
20 | "__nullptr": "cpp",
21 | "cstddef": "cpp",
22 | "exception": "cpp",
23 | "initializer_list": "cpp",
24 | "stdexcept": "cpp",
25 | "typeinfo": "cpp",
26 | "algorithm": "cpp",
27 | "__functional_03": "cpp",
28 | "__tree": "cpp",
29 | "__hash_table": "cpp",
30 | "__split_buffer": "cpp",
31 | "list": "cpp",
32 | "map": "cpp",
33 | "set": "cpp",
34 | "string": "cpp",
35 | "string_view": "cpp",
36 | "unordered_map": "cpp",
37 | "utility": "cpp",
38 | "ios": "cpp",
39 | "__locale": "cpp",
40 | "iosfwd": "cpp",
41 | "__string": "cpp",
42 | "regex": "cpp",
43 | "__functional_base_03": "cpp",
44 | "__tuple": "cpp",
45 | "array": "cpp",
46 | "deque": "cpp",
47 | "unordered_set": "cpp"
48 | },
49 | "files.exclude": {
50 | "include/spdlog": true,
51 | "extras/glfw": true,
52 | "extras/glslang": true,
53 | "extras/stb": true,
54 | "extras/tinyobjloader": false,
55 | "extras/par": true,
56 | ".debug": true,
57 | ".release": true,
58 | "**/.git": true,
59 | "**/.svn": true,
60 | "**/.hg": true,
61 | "**/CVS": true,
62 | "**/.DS_Store": true
63 | },
64 | "C_Cpp.dimInactiveRegions": false,
65 | "cSpell.enabledLanguageIds": [
66 | "asciidoc",
67 | "c",
68 | "csharp",
69 | "css",
70 | "go",
71 | "handlebars",
72 | "html",
73 | "jade",
74 | "javascript",
75 | "javascriptreact",
76 | "json",
77 | "latex",
78 | "less",
79 | "markdown",
80 | "php",
81 | "plaintext",
82 | "pub",
83 | "python",
84 | "restructuredtext",
85 | "rust",
86 | "scss",
87 | "text",
88 | "typescript",
89 | "typescriptreact",
90 | "yml"
91 | ]
92 | }
--------------------------------------------------------------------------------
/include/par/AmberApplication.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include
6 |
7 | #include
8 | #include
9 | #include
10 |
11 | namespace par {
12 |
13 | // Shields the Lava samples from the windowing system (GLFW on Desktop, native_app_glue
14 | // on Android). The entry point (main or android_main) calls createApp() and draw().
15 | struct AmberApplication {
16 | using SurfaceFn = std::function;
17 | using FactoryFn = std::function;
18 | using Registry = std::unordered_map;
19 | virtual ~AmberApplication() {}
20 | virtual void draw(double seconds) = 0;
21 | virtual void handleKey(int key) {}
22 |
23 | struct Prefs {
24 | std::string title = "amber";
25 | std::string first = "shadertoy";
26 | uint32_t width = 1794 / 2;
27 | uint32_t height = 1080 / 2;
28 | bool decorated = true;
29 | };
30 |
31 | static Prefs& prefs() {
32 | static Prefs p;
33 | return p;
34 | }
35 |
36 | static Registry& registry() {
37 | static Registry r;
38 | return r;
39 | }
40 |
41 | static Registry::iterator& current() {
42 | static Registry::iterator iter;
43 | return iter;
44 | }
45 |
46 | static AmberApplication* createApp(std::string id, SurfaceFn createSurface) {
47 | auto& iter = current();
48 | auto& reg = registry();
49 | iter = reg.find(id);
50 | assert(iter != reg.end());
51 | llog.warn("Starting {}...", iter->first);
52 | return iter->second(createSurface);
53 | }
54 |
55 | static AmberApplication* restartApp(SurfaceFn createSurface) {
56 | auto& iter = current();
57 | llog.warn("Starting {}...", iter->first);
58 | return iter->second(createSurface);
59 | }
60 |
61 | static AmberApplication* createNextApp(SurfaceFn createSurface) {
62 | auto& iter = current();
63 | auto& reg = registry();
64 | ++iter;
65 | if (iter == reg.end()) {
66 | iter = reg.begin();
67 | }
68 | llog.warn("Starting {}...", iter->first);
69 | return iter->second(createSurface);
70 | }
71 |
72 | static AmberApplication* createPreviousApp(SurfaceFn createSurface) {
73 | auto& iter = current();
74 | auto& reg = registry();
75 | ++iter;
76 | if (iter == reg.end()) {
77 | iter = reg.begin();
78 | }
79 | llog.warn("Starting {}...", iter->first);
80 | return iter->second(createSurface);
81 | }
82 |
83 | struct Register {
84 | Register(std::string id, FactoryFn createApp) { registry()[id] = createApp; }
85 | Register(Prefs p) { prefs() = p; }
86 | };
87 | };
88 |
89 | }
--------------------------------------------------------------------------------
/include/par/AmberCompiler.h:
--------------------------------------------------------------------------------
1 | // The MIT License
2 | // Copyright (c) 2018 Philip Rideout
3 |
4 | #pragma once
5 |
6 | #include
7 | #include
8 |
9 | namespace par {
10 |
11 | class AmberCompiler {
12 | public:
13 | static AmberCompiler* create() noexcept;
14 | static void operator delete(void* ptr) noexcept;
15 | enum Stage { VERTEX, FRAGMENT, COMPUTE };
16 | bool compile(Stage stage, const std::string& glsl, std::vector* spirv) const noexcept;
17 | protected:
18 | AmberCompiler() noexcept = default;
19 | // par::noncopyable
20 | AmberCompiler(AmberCompiler const&) = delete;
21 | AmberCompiler(AmberCompiler&&) = delete;
22 | AmberCompiler& operator=(AmberCompiler const&) = delete;
23 | AmberCompiler& operator=(AmberCompiler&&) = delete;
24 | };
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/include/par/AmberProgram.h:
--------------------------------------------------------------------------------
1 | // The MIT License
2 | // Copyright (c) 2018 Philip Rideout
3 |
4 | #pragma once
5 |
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | namespace par {
12 |
13 | class AmberProgram {
14 | public:
15 | using string = std::string;
16 | static AmberProgram* create(const string& vshader, const string& fshader) noexcept;
17 | static void operator delete(void* ptr) noexcept;
18 | bool compile(VkDevice device) noexcept;
19 | VkShaderModule getVertexShader() const noexcept;
20 | VkShaderModule getFragmentShader() const noexcept;
21 |
22 | // Extracts a range of text from a file, spanning from "-- chunkName" until the next "--", or
23 | // until the end of the file.
24 | static string getChunk(const string& filename, const string& chunkName) noexcept;
25 |
26 | // Monitors a folder for changes. Useful for hot-loading.
27 | using FileListener = std::function;
28 | void watchDirectory(const string& folder, FileListener onChange) noexcept;
29 | void checkDirectory() noexcept;
30 |
31 | protected:
32 | AmberProgram() noexcept = default;
33 | // par::noncopyable
34 | AmberProgram(AmberProgram const&) = delete;
35 | AmberProgram& operator=(AmberProgram const&) = delete;
36 | };
37 |
38 | #define AMBER_STRINGIFY(x) #x
39 | #define AMBER_STRINGIFY_(x) AMBER_STRINGIFY(x)
40 |
41 | #define AMBER_PREFIX_450 "#version 450\n#line " AMBER_STRINGIFY_(__LINE__) "\n"
42 | #define AMBER_PREFIX_310 "#version 310 es\n#line " AMBER_STRINGIFY_(__LINE__) "\n"
43 |
44 | #ifdef __ANDROID__
45 | #define AMBER_PREFIX AMBER_PREFIX_310
46 | #else
47 | #define AMBER_PREFIX AMBER_PREFIX_450
48 | #endif
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/include/par/LavaContext.h:
--------------------------------------------------------------------------------
1 | // The MIT License
2 | // Copyright (c) 2018 Philip Rideout
3 |
4 | #pragma once
5 |
6 | #include
7 |
8 | #include
9 |
10 | namespace par {
11 |
12 | struct LavaRecording;
13 |
14 | // The LavaContext owns the Vulkan instance, device, swap chain, and command buffers.
15 | class LavaContext {
16 | public:
17 | struct Config {
18 | bool depthBuffer;
19 | bool validation;
20 | VkSampleCountFlagBits samples;
21 | std::function createSurface;
22 | };
23 | static LavaContext* create(Config config) noexcept;
24 | static void operator delete(void* );
25 |
26 | // Starts a new command buffer and returns it.
27 | VkCommandBuffer beginFrame() noexcept;
28 |
29 | // Submits the command buffer and presents the most recently rendered image.
30 | void endFrame() noexcept;
31 |
32 | // Waits for one or two of the most recently submitted command buffers to finish.
33 | // Callers can invoke this outside a beginFrame / endFrame. Pass the default argument of -1
34 | // to wait on both command buffers in the swap chain.
35 | void waitFrame(int n = -1) noexcept;
36 |
37 | // Similar to beginFrame/endFrame/waitFrame for non-presentation work.
38 | VkCommandBuffer beginWork() noexcept;
39 | void endWork() noexcept;
40 | void waitWork() noexcept;
41 |
42 | // Allows commands to be recorded and played back later.
43 | LavaRecording* createRecording() noexcept;
44 | LavaRecording* createRecording(std::function cmdbuilder);
45 | VkCommandBuffer beginRecording(LavaRecording*, uint32_t i) noexcept;
46 | void endRecording() noexcept;
47 | void presentRecording(LavaRecording*) noexcept;
48 | void freeRecording(LavaRecording*) noexcept;
49 | void waitRecording(LavaRecording*) noexcept;
50 |
51 | // General accessors.
52 | VkInstance getInstance() const noexcept;
53 | VkSurfaceKHR getSurface() const noexcept;
54 | VkExtent2D getSize() const noexcept;
55 | VkDevice getDevice() const noexcept;
56 | VkPhysicalDevice getGpu() const noexcept;
57 | const VkPhysicalDeviceFeatures& getGpuFeatures() const noexcept;
58 | VkQueue getQueue() const noexcept;
59 | VkFormat getFormat() const noexcept;
60 | VkColorSpaceKHR getColorSpace() const noexcept;
61 | const VkPhysicalDeviceMemoryProperties& getMemoryProperties() const noexcept;
62 | VkRenderPass getRenderPass() const noexcept;
63 | VkSwapchainKHR getSwapchain() const noexcept;
64 |
65 | // Swap chain related accessors.
66 | VkImage getImage(uint32_t i = 0) const noexcept;
67 | VkImageView getImageView(uint32_t i = 0) const noexcept;
68 | VkFramebuffer getFramebuffer(uint32_t i = 0) const noexcept;
69 | VkRenderPassBeginInfo const* getBeginInfo(uint32_t i = 0) const noexcept;
70 |
71 | protected:
72 | LavaContext() noexcept = default;
73 | // par::noncopyable
74 | LavaContext(LavaContext const&) = delete;
75 | LavaContext& operator=(LavaContext const&) = delete;
76 | };
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/include/par/LavaCpuBuffer.h:
--------------------------------------------------------------------------------
1 | // The MIT License
2 | // Copyright (c) 2018 Philip Rideout
3 |
4 | #pragma once
5 |
6 | #include
7 |
8 | namespace par {
9 |
10 | class LavaCpuBuffer {
11 | public:
12 | struct Config {
13 | VkDevice device;
14 | VkPhysicalDevice gpu;
15 | uint32_t size; // Size of the upload in bytes.
16 | uint32_t capacity; // Optional capacity, must be 0 or greater than "size".
17 | void const* source; // if non-null, triggers a memcpy during construction
18 | VkBufferUsageFlags usage;
19 | };
20 | static LavaCpuBuffer* create(Config config) noexcept;
21 | static void operator delete(void* );
22 | VkBuffer getBuffer() const noexcept;
23 | void setData(void const* sourceData, uint32_t bytesToCopy,
24 | uint32_t offset = 0) noexcept;
25 | uint8_t* map() const noexcept;
26 | void unmap() const noexcept;
27 | protected:
28 | LavaCpuBuffer() noexcept = default;
29 | LavaCpuBuffer(LavaCpuBuffer const&) = delete;
30 | LavaCpuBuffer& operator=(LavaCpuBuffer const&) = delete;
31 | };
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/include/par/LavaDescCache.h:
--------------------------------------------------------------------------------
1 | // The MIT License
2 | // Copyright (c) 2018 Philip Rideout
3 |
4 | #pragma once
5 |
6 | #include
7 |
8 | #include
9 |
10 | namespace par {
11 |
12 | // Manages a set of descriptors that all conform to a specific descriptor layout.
13 | //
14 | // Creates a single VkDescriptorSetLayout upon construction and stores it as immutable state.
15 | // Accepts state changes via setUniformBuffer and setImageSampler.
16 | // Creates or fetches a descriptor set when getDescriptor() is called.
17 | // Optionally frees least-recently-used descriptors via releaseUnused().
18 | //
19 | class LavaDescCache {
20 | public:
21 | struct Config {
22 | VkDevice device;
23 | std::vector uniformBuffers;
24 | std::vector imageSamplers;
25 | std::vector inputAttachments;
26 | };
27 | static LavaDescCache* create(Config config) noexcept;
28 | static void operator delete(void* );
29 |
30 | // Fetches the descriptor set layout that was created at construction.
31 | VkDescriptorSetLayout getLayout() const noexcept;
32 |
33 | // Fetches or creates a VkDescriptorSet corresponding to the layout that was established
34 | // during construction. Immediately calls vkUpdateDescriptorSets if a new descriptor set was
35 | // constructed. The caller is responsible for calling vkCmdBindDescriptorSet.
36 | VkDescriptorSet getDescriptor() noexcept;
37 |
38 | // Similar to getDescriptor but returns a weak reference for convenience.
39 | VkDescriptorSet* getDescPointer() noexcept;
40 |
41 | // Fetches or creates a VkDescriptorSet corresponding to the layout that was established
42 | // during construction. Returns true if the client should call vkCmdBindDescriptorSet.
43 | // Sets "writes" to a non-empty vector if the client should call vkUpdateDescriptorSets.
44 | bool getDescriptorSet(VkDescriptorSet* descriptorSet,
45 | std::vector* writes) noexcept;
46 |
47 | void setUniformBuffer(uint32_t bindingIndex, VkBuffer uniformBuffer) noexcept;
48 | void setImageSampler(uint32_t bindingIndex, VkDescriptorImageInfo binding) noexcept;
49 | void setInputAttachment(uint32_t bindingIndex, VkDescriptorImageInfo binding) noexcept;
50 |
51 | void unsetUniformBuffer(VkBuffer uniformBuffer) noexcept;
52 | void unsetImageSampler(VkDescriptorImageInfo binding) noexcept;
53 | void unsetInputAttachment(VkDescriptorImageInfo binding) noexcept;
54 |
55 | // Frees descriptor sets that were last retrieved more than N milliseconds ago, and more than
56 | // M frames ago. Also bumps the internal frame count.
57 | void evictDescriptors(uint64_t milliseconds, uint64_t nframes) noexcept;
58 | protected:
59 | LavaDescCache() noexcept = default;
60 | // par::noncopyable
61 | LavaDescCache(LavaDescCache const&) = delete;
62 | LavaDescCache& operator=(LavaDescCache const&) = delete;
63 | };
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/include/par/LavaGpuBuffer.h:
--------------------------------------------------------------------------------
1 | // The MIT License
2 | // Copyright (c) 2018 Philip Rideout
3 |
4 | #pragma once
5 |
6 | #include
7 |
8 | namespace par {
9 |
10 | class LavaGpuBuffer {
11 | public:
12 | struct Config {
13 | VkDevice device;
14 | VkPhysicalDevice gpu;
15 | uint32_t size;
16 | VkBufferUsageFlags usage;
17 | };
18 | static LavaGpuBuffer* create(Config config) noexcept;
19 | static void operator delete(void* );
20 | VkBuffer getBuffer() const noexcept;
21 | const VkBuffer* getBufferPtr() const noexcept;
22 | protected:
23 | LavaGpuBuffer() noexcept = default;
24 | // par::noncopyable
25 | LavaGpuBuffer(LavaGpuBuffer const&) = delete;
26 | LavaGpuBuffer& operator=(LavaGpuBuffer const&) = delete;
27 | };
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/include/par/LavaLog.h:
--------------------------------------------------------------------------------
1 | // The MIT License
2 | // Copyright (c) 2018 Philip Rideout
3 |
4 | #pragma once
5 |
6 | #include
7 | #include
8 |
9 | #include
10 | #include
11 |
12 | #define LOG_CHECK(condition, msg) if (!(condition)) llog.fatal("{}:{} {}", __FILE__, __LINE__, msg);
13 |
14 | #ifdef NDEBUG
15 | #define LOG_DCHECK(condition, msg)
16 | #else
17 | #define LOG_DCHECK(condition, msg) LOG_CHECK(condition, msg)
18 | #endif
19 |
20 | namespace par {
21 |
22 | class LavaLog {
23 | public:
24 | LavaLog();
25 |
26 | template
27 | void trace(const char *fmt, const Arg1 &, const Args &... args) const noexcept;
28 |
29 | template
30 | void debug(const char *fmt, const Arg1 &, const Args &... args) const noexcept;
31 |
32 | template
33 | void info(const char *fmt, const Arg1 &, const Args &... args) const noexcept;
34 |
35 | template
36 | void warn(const char *fmt, const Arg1 &, const Args &... args) const noexcept;
37 |
38 | template
39 | void error(const char *fmt, const Arg1 &, const Args &... args) const noexcept;
40 |
41 | template
42 | void fatal(const char *fmt, const Arg1 &, const Args &... args) const noexcept;
43 |
44 | template
45 | void trace(const T &msg) const noexcept;
46 |
47 | template
48 | void debug(const T &msg) const noexcept;
49 |
50 | template
51 | void info(const T &msg) const noexcept;
52 |
53 | template
54 | void warn(const T &msg) const noexcept;
55 |
56 | template
57 | void error(const T &msg) const noexcept;
58 |
59 | template
60 | void fatal(const T &msg) const noexcept;
61 |
62 | private:
63 | std::shared_ptr mLogger;
64 | };
65 |
66 | extern LavaLog llog;
67 |
68 | template
69 | inline void LavaLog::trace(const char *fmt, const Arg1 &arg1, const Args &... args) const noexcept {
70 | mLogger->log(spdlog::level::trace, fmt, arg1, args...);
71 | }
72 |
73 | template
74 | inline void LavaLog::debug(const char *fmt, const Arg1 &arg1, const Args &... args) const noexcept {
75 | mLogger->log(spdlog::level::debug, fmt, arg1, args...);
76 | }
77 |
78 | template
79 | inline void LavaLog::info(const char *fmt, const Arg1 &arg1, const Args &... args) const noexcept {
80 | mLogger->log(spdlog::level::info, fmt, arg1, args...);
81 | }
82 |
83 | template
84 | inline void LavaLog::warn(const char *fmt, const Arg1 &arg1, const Args &... args) const noexcept {
85 | mLogger->log(spdlog::level::warn, fmt, arg1, args...);
86 | }
87 |
88 | template
89 | inline void LavaLog::error(const char *fmt, const Arg1 &arg1, const Args &... args) const noexcept {
90 | mLogger->log(spdlog::level::err, fmt, arg1, args...);
91 | }
92 |
93 | template
94 | inline void LavaLog::fatal(const char *f, const Arg1 &arg, const Args &... args) const noexcept {
95 | mLogger->log(spdlog::level::err, f, arg, args...);
96 | std::raise(SIGTRAP);
97 | }
98 |
99 | template
100 | inline void LavaLog::trace(const T &msg) const noexcept {
101 | mLogger->log(spdlog::level::trace, msg);
102 | }
103 |
104 | template
105 | inline void LavaLog::debug(const T &msg) const noexcept {
106 | mLogger->log(spdlog::level::debug, msg);
107 | }
108 |
109 | template
110 | inline void LavaLog::info(const T &msg) const noexcept {
111 | mLogger->log(spdlog::level::info, msg);
112 | }
113 |
114 | template
115 | inline void LavaLog::warn(const T &msg) const noexcept {
116 | mLogger->log(spdlog::level::warn, msg);
117 | }
118 |
119 | template
120 | inline void LavaLog::error(const T &msg) const noexcept {
121 | mLogger->log(spdlog::level::err, msg);
122 | }
123 |
124 | template
125 | inline void LavaLog::fatal(const T &msg) const noexcept {
126 | mLogger->log(spdlog::level::err, msg);
127 | std::raise(SIGTRAP);
128 | }
129 |
130 | }
131 |
--------------------------------------------------------------------------------
/include/par/LavaPipeCache.h:
--------------------------------------------------------------------------------
1 | // The MIT License
2 | // Copyright (c) 2018 Philip Rideout
3 |
4 | #pragma once
5 |
6 | #include
7 |
8 | #include
9 |
10 | namespace par {
11 |
12 | // Manages a set of pipeline objects that all conform to a specific pipeline layout.
13 | //
14 | // Creates a single VkPipelineLayout upon construction and stores it as immutable state.
15 | // Accepts state changes via setRasterState, setVertexState, set*Shader, and setRenderPass.
16 | // Creates or fetches a pipeline when getPipeline() is called.
17 | // Optionally frees least-recently-used pipelines via releaseUnused().
18 | //
19 | class LavaPipeCache {
20 | public:
21 | struct RasterState {
22 | VkPipelineRasterizationStateCreateInfo rasterization;
23 | VkPipelineColorBlendAttachmentState blending;
24 | VkPipelineDepthStencilStateCreateInfo depthStencil;
25 | VkPipelineMultisampleStateCreateInfo multisampling;
26 | };
27 | struct VertexState {
28 | VkPrimitiveTopology topology;
29 | std::vector attributes;
30 | std::vector buffers;
31 | };
32 | struct Config {
33 | VkDevice device;
34 | std::vector descriptorLayouts;
35 | VkRenderPass renderPass;
36 | VkShaderModule vshader;
37 | VkShaderModule fshader;
38 | VertexState vertex;
39 | };
40 | static LavaPipeCache* create(Config config) noexcept;
41 | static void operator delete(void* );
42 |
43 | // Fetches the pipeline layout that was created at construction.
44 | VkPipelineLayout getLayout() const noexcept;
45 |
46 | // Fetches or creates a VkPipeline object corresponding to the layout that was established
47 | // during construction, as well as the current state (see setRasterState et al).
48 | VkPipeline getPipeline() noexcept;
49 |
50 | // Returns true if the client should call vkCmdBindPipeline.
51 | bool getPipeline(VkPipeline* pipeline) noexcept;
52 |
53 | const RasterState& getDefaultRasterState() const noexcept;
54 | void setRasterState(const RasterState& rasterState) noexcept;
55 | void setVertexState(const VertexState& varray) noexcept;
56 | void setVertexShader(VkShaderModule module) noexcept;
57 | void setFragmentShader(VkShaderModule module) noexcept;
58 | void setRenderPass(VkRenderPass renderPass) noexcept;
59 |
60 | // Evicts pipeline objects that were last used more than N milliseconds ago.
61 | void releaseUnused(uint64_t milliseconds) noexcept;
62 | protected:
63 | LavaPipeCache() noexcept = default;
64 | // par::noncopyable
65 | LavaPipeCache(LavaPipeCache const&) = delete;
66 | LavaPipeCache& operator=(LavaPipeCache const&) = delete;
67 | };
68 |
69 | using LavaVertex = LavaPipeCache::VertexState;
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/include/par/LavaSurfCache.h:
--------------------------------------------------------------------------------
1 | // The MIT License
2 | // Copyright (c) 2018 Philip Rideout
3 |
4 | #pragma once
5 |
6 | #include
7 |
8 | namespace par {
9 |
10 | // Creates offscreen rendering surfaces, manages a cache of VkFramebuffer and VkRenderPass.
11 | class LavaSurfCache {
12 | public:
13 | struct Config;
14 | struct Attachment;
15 | struct Params;
16 | struct AttachmentConfig;
17 |
18 | // Construction / Destruction.
19 | static LavaSurfCache* create(const Config& config) noexcept;
20 | static void operator delete(void* );
21 |
22 | // Factory functions for VkImage / VkImageLayout.
23 | Attachment const* createColorAttachment(const AttachmentConfig& config) const noexcept;
24 | void finalizeAttachment(Attachment const* attachment, VkCommandBuffer cmdbuf) const noexcept;
25 | void finalizeAttachment(Attachment const* attachment, VkCommandBuffer cmdbuf,
26 | VkBuffer srcData, uint32_t nbytes) const noexcept;
27 | void finalizeAttachment(Attachment const* attachment, VkCommandBuffer cmdbuf,
28 | const VkClearColorValue& clearColor) const noexcept;
29 | void freeAttachment(Attachment const* attachment) const noexcept;
30 |
31 | // Cache retrieval / creation / eviction.
32 | VkFramebuffer getFramebuffer(const Params& params) noexcept;
33 | VkRenderPass getRenderPass(const Params& params, VkRenderPassBeginInfo* = nullptr) noexcept;
34 | void releaseUnused(uint64_t milliseconds) noexcept;
35 |
36 | struct Config {
37 | VkDevice device;
38 | VkPhysicalDevice gpu;
39 | };
40 |
41 | struct AttachmentConfig {
42 | uint32_t width;
43 | uint32_t height;
44 | VkFormat format;
45 | bool enableUpload;
46 | bool enableRead;
47 | };
48 |
49 | struct Attachment {
50 | VkImage image;
51 | VkImageView imageView;
52 | uint32_t width;
53 | uint32_t height;
54 | VkFormat format;
55 | };
56 |
57 | struct Params {
58 | Attachment const* color;
59 | Attachment const* depth;
60 | VkAttachmentLoadOp colorLoad;
61 | VkAttachmentLoadOp depthLoad;
62 | VkClearValue clearColor;
63 | VkClearValue clearDepth;
64 | };
65 |
66 | protected:
67 | LavaSurfCache() noexcept = default;
68 | LavaSurfCache(LavaSurfCache const&) = delete;
69 | LavaSurfCache& operator=(LavaSurfCache const&) = delete;
70 | };
71 |
72 | using LavaSurface = LavaSurfCache::Params;
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/include/par/LavaTexture.h:
--------------------------------------------------------------------------------
1 | // The MIT License
2 | // Copyright (c) 2018 Philip Rideout
3 |
4 | #pragma once
5 |
6 | #include
7 |
8 | namespace par {
9 |
10 | class LavaTexture {
11 | public:
12 | struct Config {
13 | VkDevice device;
14 | VkPhysicalDevice gpu;
15 | uint32_t size;
16 | void const* source;
17 | uint32_t width;
18 | uint32_t height;
19 | VkFormat format;
20 | };
21 | static LavaTexture* create(Config config) noexcept;
22 | static void operator delete(void* ptr) noexcept;
23 | void uploadStage(VkCommandBuffer cmd) const noexcept;
24 | void freeStage() noexcept;
25 | VkImageView getImageView() const noexcept;
26 | protected:
27 | LavaTexture() noexcept = default;
28 | // par::noncopyable
29 | LavaTexture(LavaTexture const&) = delete;
30 | LavaTexture& operator=(LavaTexture const&) = delete;
31 | };
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/include/spdlog/async_logger.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright(c) 2015 Gabi Melman.
3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
4 | //
5 |
6 | #pragma once
7 |
8 | // Very fast asynchronous logger (millions of logs per second on an average desktop)
9 | // Uses pre allocated lockfree queue for maximum throughput even under large number of threads.
10 | // Creates a single back thread to pop messages from the queue and log them.
11 | //
12 | // Upon each log write the logger:
13 | // 1. Checks if its log level is enough to log the message
14 | // 2. Push a new copy of the message to a queue (or block the caller until space is available in the queue)
15 | // 3. will throw spdlog_ex upon log exceptions
16 | // Upon destruction, logs all remaining messages in the queue before destructing..
17 |
18 | #include "common.h"
19 | #include "logger.h"
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | namespace spdlog {
27 |
28 | namespace details {
29 | class async_log_helper;
30 | }
31 |
32 | class async_logger SPDLOG_FINAL : public logger
33 | {
34 | public:
35 | template
36 | async_logger(const std::string &logger_name, const It &begin, const It &end, size_t queue_size,
37 | const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
38 | const std::function &worker_warmup_cb = nullptr,
39 | const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),
40 | const std::function &worker_teardown_cb = nullptr);
41 |
42 | async_logger(const std::string &logger_name, sinks_init_list sinks, size_t queue_size,
43 | const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
44 | const std::function &worker_warmup_cb = nullptr,
45 | const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),
46 | const std::function &worker_teardown_cb = nullptr);
47 |
48 | async_logger(const std::string &logger_name, sink_ptr single_sink, size_t queue_size,
49 | const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
50 | const std::function &worker_warmup_cb = nullptr,
51 | const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),
52 | const std::function &worker_teardown_cb = nullptr);
53 |
54 | // Wait for the queue to be empty, and flush synchronously
55 | // Warning: this can potentially last forever as we wait it to complete
56 | void flush() override;
57 |
58 | // Error handler
59 | void set_error_handler(log_err_handler) override;
60 | log_err_handler error_handler() override;
61 |
62 | protected:
63 | void _sink_it(details::log_msg &msg) override;
64 | void _set_formatter(spdlog::formatter_ptr msg_formatter) override;
65 | void _set_pattern(const std::string &pattern, pattern_time_type pattern_time) override;
66 |
67 | private:
68 | std::unique_ptr _async_log_helper;
69 | };
70 | } // namespace spdlog
71 |
72 | #include "details/async_logger_impl.h"
73 |
--------------------------------------------------------------------------------
/include/spdlog/common.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright(c) 2015 Gabi Melman.
3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
4 | //
5 |
6 | #pragma once
7 |
8 | #define SPDLOG_VERSION "0.16.4-rc"
9 |
10 | #include "tweakme.h"
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
22 | #include
23 | #include
24 | #endif
25 |
26 | #include "details/null_mutex.h"
27 |
28 | // visual studio upto 2013 does not support noexcept nor constexpr
29 | #if defined(_MSC_VER) && (_MSC_VER < 1900)
30 | #define SPDLOG_NOEXCEPT throw()
31 | #define SPDLOG_CONSTEXPR
32 | #else
33 | #define SPDLOG_NOEXCEPT noexcept
34 | #define SPDLOG_CONSTEXPR constexpr
35 | #endif
36 |
37 | // final keyword support. On by default. See tweakme.h
38 | #if defined(SPDLOG_NO_FINAL)
39 | #define SPDLOG_FINAL
40 | #else
41 | #define SPDLOG_FINAL final
42 | #endif
43 |
44 | #if defined(__GNUC__) || defined(__clang__)
45 | #define SPDLOG_DEPRECATED __attribute__((deprecated))
46 | #elif defined(_MSC_VER)
47 | #define SPDLOG_DEPRECATED __declspec(deprecated)
48 | #else
49 | #define SPDLOG_DEPRECATED
50 | #endif
51 |
52 | #include "fmt/fmt.h"
53 |
54 | namespace spdlog {
55 |
56 | class formatter;
57 |
58 | namespace sinks {
59 | class sink;
60 | }
61 |
62 | using log_clock = std::chrono::system_clock;
63 | using sink_ptr = std::shared_ptr;
64 | using sinks_init_list = std::initializer_list;
65 | using formatter_ptr = std::shared_ptr;
66 | #if defined(SPDLOG_NO_ATOMIC_LEVELS)
67 | using level_t = details::null_atomic_int;
68 | #else
69 | using level_t = std::atomic;
70 | #endif
71 |
72 | using log_err_handler = std::function;
73 |
74 | // Log level enum
75 | namespace level {
76 | enum level_enum
77 | {
78 | trace = 0,
79 | debug = 1,
80 | info = 2,
81 | warn = 3,
82 | err = 4,
83 | critical = 5,
84 | off = 6
85 | };
86 |
87 | #if !defined(SPDLOG_LEVEL_NAMES)
88 | #define SPDLOG_LEVEL_NAMES \
89 | { \
90 | "trace", "debug", "info", "warning", "error", "critical", "off" \
91 | }
92 | #endif
93 | static const char *level_names[] SPDLOG_LEVEL_NAMES;
94 |
95 | static const char *short_level_names[]{"T", "D", "I", "W", "E", "C", "O"};
96 |
97 | inline const char *to_str(spdlog::level::level_enum l)
98 | {
99 | return level_names[l];
100 | }
101 |
102 | inline const char *to_short_str(spdlog::level::level_enum l)
103 | {
104 | return short_level_names[l];
105 | }
106 | inline spdlog::level::level_enum from_str(const std::string &name)
107 | {
108 | static std::unordered_map name_to_level = // map string->level
109 | {{level_names[0], level::trace}, // trace
110 | {level_names[1], level::debug}, // debug
111 | {level_names[2], level::info}, // info
112 | {level_names[3], level::warn}, // warn
113 | {level_names[4], level::err}, // err
114 | {level_names[5], level::critical}, // critical
115 | {level_names[6], level::off}}; // off
116 |
117 | auto lvl_it = name_to_level.find(name);
118 | return lvl_it != name_to_level.end() ? lvl_it->second : level::off;
119 | }
120 |
121 | using level_hasher = std::hash;
122 | } // namespace level
123 |
124 | //
125 | // Async overflow policy - block by default.
126 | //
127 | enum class async_overflow_policy
128 | {
129 | block_retry, // Block / yield / sleep until message can be enqueued
130 | discard_log_msg // Discard the message it enqueue fails
131 | };
132 |
133 | //
134 | // Pattern time - specific time getting to use for pattern_formatter.
135 | // local time by default
136 | //
137 | enum class pattern_time_type
138 | {
139 | local, // log localtime
140 | utc // log utc
141 | };
142 |
143 | //
144 | // Log exception
145 | //
146 | namespace details {
147 | namespace os {
148 | std::string errno_str(int err_num);
149 | }
150 | } // namespace details
151 | class spdlog_ex : public std::exception
152 | {
153 | public:
154 | explicit spdlog_ex(std::string msg)
155 | : _msg(std::move(msg))
156 | {
157 | }
158 |
159 | spdlog_ex(const std::string &msg, int last_errno)
160 | {
161 | _msg = msg + ": " + details::os::errno_str(last_errno);
162 | }
163 |
164 | const char *what() const SPDLOG_NOEXCEPT override
165 | {
166 | return _msg.c_str();
167 | }
168 |
169 | private:
170 | std::string _msg;
171 | };
172 |
173 | //
174 | // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
175 | //
176 | #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
177 | using filename_t = std::wstring;
178 | #else
179 | using filename_t = std::string;
180 | #endif
181 |
182 | } // namespace spdlog
183 |
--------------------------------------------------------------------------------
/include/spdlog/contrib/README.md:
--------------------------------------------------------------------------------
1 | Please put here your contribs. Popular contribs will be moved to main tree after stablization
2 |
--------------------------------------------------------------------------------
/include/spdlog/contrib/sinks/.gitignore:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/include/spdlog/contrib/sinks/step_file_sink.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../../details/file_helper.h"
4 | #include "../../details/null_mutex.h"
5 | #include "../../fmt/fmt.h"
6 | #include "../../sinks/base_sink.h"
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | // Example for spdlog.h
17 | //
18 | // Create a file logger which creates new files with a specified time step and fixed file size:
19 | //
20 | // std::shared_ptr step_logger_mt(const std::string &logger_name, const filename_t &filename, unsigned seconds = 60, const filename_t &tmp_ext = ".tmp", unsigned max_file_size = std::numeric_limits::max());
21 | // std::shared_ptr step_logger_st(const std::string &logger_name, const filename_t &filename, unsigned seconds = 60, const filename_t &tmp_ext = ".tmp", unsigned max_file_size = std::numeric_limits::max();;
22 |
23 | // Example for spdlog_impl.h
24 | // Create a file logger that creates new files with a specified increment
25 | // inline std::shared_ptr spdlog::step_logger_mt(
26 | // const std::string &logger_name, const filename_t &filename_fmt, unsigned seconds, const filename_t &tmp_ext, unsigned max_file_size)
27 | // {
28 | // return create(logger_name, filename_fmt, seconds, tmp_ext, max_file_size);
29 | // }
30 |
31 | // inline std::shared_ptr spdlog::step_logger_st(
32 | // const std::string &logger_name, const filename_t &filename_fmt, unsigned seconds, const filename_t &tmp_ext, unsigned max_file_size)
33 | // {
34 | // return create(logger_name, filename_fmt, seconds, tmp_ext, max_file_size);
35 | // }
36 |
37 | namespace spdlog {
38 | namespace sinks {
39 |
40 | /*
41 | * Default generator of step log file names.
42 | */
43 | struct default_step_file_name_calculator
44 | {
45 | // Create filename for the form filename_YYYY-MM-DD_hh-mm-ss.ext
46 | static std::tuple calc_filename(const filename_t &filename, const filename_t &tmp_ext)
47 | {
48 | std::tm tm = spdlog::details::os::localtime();
49 | filename_t basename, ext;
50 | std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename);
51 | std::conditional::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w;
52 | w.write(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}-{:02d}{}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
53 | tm.tm_hour, tm.tm_min, tm.tm_sec, tmp_ext);
54 | return std::make_tuple(w.str(), ext);
55 | }
56 | };
57 |
58 | /*
59 | * Rotating file sink based on size and a specified time step
60 | */
61 | template
62 | class step_file_sink SPDLOG_FINAL : public base_sink
63 | {
64 | public:
65 | step_file_sink(filename_t base_filename, unsigned step_seconds, filename_t tmp_ext, unsigned max_size)
66 | : _base_filename(std::move(base_filename))
67 | , _tmp_ext(std::move(tmp_ext))
68 | , _step_seconds(step_seconds)
69 | , _max_size(max_size)
70 | {
71 | if (step_seconds == 0)
72 | {
73 | throw spdlog_ex("step_file_sink: Invalid time step in ctor");
74 | }
75 | if (max_size == 0)
76 | {
77 | throw spdlog_ex("step_file_sink: Invalid max log size in ctor");
78 | }
79 |
80 | _tp = _next_tp();
81 | std::tie(_current_filename, _ext) = FileNameCalc::calc_filename(_base_filename, _tmp_ext);
82 |
83 | if (_tmp_ext == _ext)
84 | {
85 | throw spdlog_ex("step_file_sink: The temporary extension matches the specified in ctor");
86 | }
87 |
88 | _file_helper.open(_current_filename);
89 | _current_size = _file_helper.size(); // expensive. called only once
90 | }
91 |
92 | ~step_file_sink()
93 | {
94 | using details::os::filename_to_str;
95 |
96 | filename_t src =_current_filename, target;
97 | std::tie(target, std::ignore) = details::file_helper::split_by_extenstion(src);
98 | target += _ext;
99 |
100 | details::os::rename(src, target);
101 | }
102 |
103 | protected:
104 | void _sink_it(const details::log_msg &msg) override
105 | {
106 | _current_size += msg.formatted.size();
107 | if (std::chrono::system_clock::now() >= _tp || _current_size > _max_size)
108 | {
109 | close_current_file();
110 |
111 | std::tie(_current_filename, std::ignore) = FileNameCalc::calc_filename(_base_filename, _tmp_ext);
112 | _file_helper.open(_current_filename);
113 | _tp = _next_tp();
114 | _current_size = msg.formatted.size();
115 | }
116 | _file_helper.write(msg);
117 | }
118 |
119 | void _flush() override
120 | {
121 | _file_helper.flush();
122 | }
123 |
124 | private:
125 | std::chrono::system_clock::time_point _next_tp()
126 | {
127 | return std::chrono::system_clock::now() + _step_seconds;
128 | }
129 |
130 | void close_current_file()
131 | {
132 | using details::os::filename_to_str;
133 |
134 | filename_t src =_current_filename, target;
135 | std::tie(target, std::ignore) = details::file_helper::split_by_extenstion(src);
136 | target += _ext;
137 |
138 | if (details::file_helper::file_exists(src) && details::os::rename(src, target) != 0)
139 | {
140 | throw spdlog_ex("step_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target), errno);
141 | }
142 | }
143 |
144 | const filename_t _base_filename;
145 | const filename_t _tmp_ext;
146 | const std::chrono::seconds _step_seconds;
147 | const unsigned _max_size;
148 |
149 | std::chrono::system_clock::time_point _tp;
150 | filename_t _current_filename;
151 | filename_t _ext;
152 | unsigned _current_size;
153 |
154 | details::file_helper _file_helper;
155 | };
156 |
157 | using step_file_sink_mt = step_file_sink;
158 | using step_file_sink_st = step_file_sink;
159 |
160 | } // namespace sinks
161 | } // namespace spdlog
162 |
--------------------------------------------------------------------------------
/include/spdlog/details/async_logger_impl.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright(c) 2015 Gabi Melman.
3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
4 | //
5 |
6 | #pragma once
7 |
8 | // Async Logger implementation
9 | // Use an async_sink (queue per logger) to perform the logging in a worker thread
10 |
11 | #include "../async_logger.h"
12 | #include "../details/async_log_helper.h"
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | template
20 | inline spdlog::async_logger::async_logger(const std::string &logger_name, const It &begin, const It &end, size_t queue_size,
21 | const async_overflow_policy overflow_policy, const std::function &worker_warmup_cb,
22 | const std::chrono::milliseconds &flush_interval_ms, const std::function &worker_teardown_cb)
23 | : logger(logger_name, begin, end)
24 | , _async_log_helper(new details::async_log_helper(
25 | _formatter, _sinks, queue_size, _err_handler, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb))
26 | {
27 | }
28 |
29 | inline spdlog::async_logger::async_logger(const std::string &logger_name, sinks_init_list sinks_list, size_t queue_size,
30 | const async_overflow_policy overflow_policy, const std::function &worker_warmup_cb,
31 | const std::chrono::milliseconds &flush_interval_ms, const std::function &worker_teardown_cb)
32 | : async_logger(logger_name, sinks_list.begin(), sinks_list.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms,
33 | worker_teardown_cb)
34 | {
35 | }
36 |
37 | inline spdlog::async_logger::async_logger(const std::string &logger_name, sink_ptr single_sink, size_t queue_size,
38 | const async_overflow_policy overflow_policy, const std::function &worker_warmup_cb,
39 | const std::chrono::milliseconds &flush_interval_ms, const std::function &worker_teardown_cb)
40 | : async_logger(
41 | logger_name, {std::move(single_sink)}, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb)
42 | {
43 | }
44 |
45 | inline void spdlog::async_logger::flush()
46 | {
47 | _async_log_helper->flush(true);
48 | }
49 |
50 | // Error handler
51 | inline void spdlog::async_logger::set_error_handler(spdlog::log_err_handler err_handler)
52 | {
53 | _err_handler = err_handler;
54 | _async_log_helper->set_error_handler(err_handler);
55 | }
56 | inline spdlog::log_err_handler spdlog::async_logger::error_handler()
57 | {
58 | return _err_handler;
59 | }
60 |
61 | inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter)
62 | {
63 | _formatter = msg_formatter;
64 | _async_log_helper->set_formatter(_formatter);
65 | }
66 |
67 | inline void spdlog::async_logger::_set_pattern(const std::string &pattern, pattern_time_type pattern_time)
68 | {
69 | _formatter = std::make_shared(pattern, pattern_time);
70 | _async_log_helper->set_formatter(_formatter);
71 | }
72 |
73 | inline void spdlog::async_logger::_sink_it(details::log_msg &msg)
74 | {
75 | try
76 | {
77 | #if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)
78 | _incr_msg_counter(msg);
79 | #endif
80 | _async_log_helper->log(msg);
81 | if (_should_flush_on(msg))
82 | {
83 | _async_log_helper->flush(false); // do async flush
84 | }
85 | }
86 | catch (const std::exception &ex)
87 | {
88 | _err_handler(ex.what());
89 | }
90 | catch (...)
91 | {
92 | _err_handler("Unknown exception in logger " + _name);
93 | throw;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/include/spdlog/details/file_helper.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright(c) 2015 Gabi Melman.
3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
4 | //
5 |
6 | #pragma once
7 |
8 | // Helper class for file sink
9 | // When failing to open a file, retry several times(5) with small delay between the tries(10 ms)
10 | // Throw spdlog_ex exception on errors
11 |
12 | #include "../details/log_msg.h"
13 | #include "../details/os.h"
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 |
22 | namespace spdlog {
23 | namespace details {
24 |
25 | class file_helper
26 | {
27 |
28 | public:
29 | const int open_tries = 5;
30 | const int open_interval = 10;
31 |
32 | explicit file_helper() = default;
33 |
34 | file_helper(const file_helper &) = delete;
35 | file_helper &operator=(const file_helper &) = delete;
36 |
37 | ~file_helper()
38 | {
39 | close();
40 | }
41 |
42 | void open(const filename_t &fname, bool truncate = false)
43 | {
44 | close();
45 | auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab");
46 | _filename = fname;
47 | for (int tries = 0; tries < open_tries; ++tries)
48 | {
49 | if (!os::fopen_s(&_fd, fname, mode))
50 | {
51 | return;
52 | }
53 |
54 | details::os::sleep_for_millis(open_interval);
55 | }
56 |
57 | throw spdlog_ex("Failed opening file " + os::filename_to_str(_filename) + " for writing", errno);
58 | }
59 |
60 | void reopen(bool truncate)
61 | {
62 | if (_filename.empty())
63 | {
64 | throw spdlog_ex("Failed re opening file - was not opened before");
65 | }
66 | open(_filename, truncate);
67 | }
68 |
69 | void flush()
70 | {
71 | std::fflush(_fd);
72 | }
73 |
74 | void close()
75 | {
76 | if (_fd != nullptr)
77 | {
78 | std::fclose(_fd);
79 | _fd = nullptr;
80 | }
81 | }
82 |
83 | void write(const log_msg &msg)
84 | {
85 | size_t msg_size = msg.formatted.size();
86 | auto data = msg.formatted.data();
87 | if (std::fwrite(data, 1, msg_size, _fd) != msg_size)
88 | {
89 | throw spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno);
90 | }
91 | }
92 |
93 | size_t size() const
94 | {
95 | if (_fd == nullptr)
96 | {
97 | throw spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename));
98 | }
99 | return os::filesize(_fd);
100 | }
101 |
102 | const filename_t &filename() const
103 | {
104 | return _filename;
105 | }
106 |
107 | static bool file_exists(const filename_t &fname)
108 | {
109 | return os::file_exists(fname);
110 | }
111 |
112 | //
113 | // return file path and its extension:
114 | //
115 | // "mylog.txt" => ("mylog", ".txt")
116 | // "mylog" => ("mylog", "")
117 | // "mylog." => ("mylog.", "")
118 | // "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
119 | //
120 | // the starting dot in filenames is ignored (hidden files):
121 | //
122 | // ".mylog" => (".mylog". "")
123 | // "my_folder/.mylog" => ("my_folder/.mylog", "")
124 | // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
125 | static std::tuple split_by_extenstion(const spdlog::filename_t &fname)
126 | {
127 | auto ext_index = fname.rfind('.');
128 |
129 | // no valid extension found - return whole path and empty string as extension
130 | if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1)
131 | {
132 | return std::make_tuple(fname, spdlog::filename_t());
133 | }
134 |
135 | // treat casese like "/etc/rc.d/somelogfile or "/abc/.hiddenfile"
136 | auto folder_index = fname.rfind(details::os::folder_sep);
137 | if (folder_index != fname.npos && folder_index >= ext_index - 1)
138 | {
139 | return std::make_tuple(fname, spdlog::filename_t());
140 | }
141 |
142 | // finally - return a valid base and extension tuple
143 | return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));
144 | }
145 |
146 | private:
147 | FILE *_fd{nullptr};
148 | filename_t _filename;
149 | };
150 | } // namespace details
151 | } // namespace spdlog
152 |
--------------------------------------------------------------------------------
/include/spdlog/details/log_msg.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright(c) 2015 Gabi Melman.
3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
4 | //
5 |
6 | #pragma once
7 |
8 | #include "../common.h"
9 | #include "../details/os.h"
10 |
11 | #include
12 | #include
13 |
14 | namespace spdlog {
15 | namespace details {
16 | struct log_msg
17 | {
18 | log_msg() = default;
19 | log_msg(const std::string *loggers_name, level::level_enum lvl)
20 | : logger_name(loggers_name)
21 | , level(lvl)
22 | {
23 | #ifndef SPDLOG_NO_DATETIME
24 | time = os::now();
25 | #endif
26 |
27 | #ifndef SPDLOG_NO_THREAD_ID
28 | thread_id = os::thread_id();
29 | #endif
30 | }
31 |
32 | log_msg(const log_msg &other) = delete;
33 | log_msg &operator=(log_msg &&other) = delete;
34 | log_msg(log_msg &&other) = delete;
35 |
36 | const std::string *logger_name{nullptr};
37 | level::level_enum level;
38 | log_clock::time_point time;
39 | size_t thread_id;
40 | fmt::MemoryWriter raw;
41 | fmt::MemoryWriter formatted;
42 | size_t msg_id{0};
43 | // wrap this range with color codes
44 | size_t color_range_start{0};
45 | size_t color_range_end{0};
46 | };
47 | } // namespace details
48 | } // namespace spdlog
49 |
--------------------------------------------------------------------------------
/include/spdlog/details/mpmc_bounded_q.h:
--------------------------------------------------------------------------------
1 | /*
2 | A modified version of Bounded MPMC queue by Dmitry Vyukov.
3 |
4 | Original code from:
5 | http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
6 |
7 | licensed by Dmitry Vyukov under the terms below:
8 |
9 | Simplified BSD license
10 |
11 | Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
12 | Redistribution and use in source and binary forms, with or without modification,
13 | are permitted provided that the following conditions are met:
14 | 1. Redistributions of source code must retain the above copyright notice, this list of
15 | conditions and the following disclaimer.
16 |
17 | 2. Redistributions in binary form must reproduce the above copyright notice, this list
18 | of conditions and the following disclaimer in the documentation and/or other materials
19 | provided with the distribution.
20 |
21 | THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
22 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24 | SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
27 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
32 | The views and conclusions contained in the software and documentation are those of the authors and
33 | should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov.
34 | */
35 |
36 | /*
37 | The code in its current form adds the license below:
38 |
39 | Copyright(c) 2015 Gabi Melman.
40 | Distributed under the MIT License (http://opensource.org/licenses/MIT)
41 |
42 | */
43 |
44 | #pragma once
45 |
46 | #include "../common.h"
47 |
48 | #include
49 | #include
50 |
51 | namespace spdlog {
52 | namespace details {
53 |
54 | template
55 | class mpmc_bounded_queue
56 | {
57 | public:
58 | using item_type = T;
59 |
60 | explicit mpmc_bounded_queue(size_t buffer_size)
61 | : max_size_(buffer_size)
62 | , buffer_(new cell_t[buffer_size])
63 | , buffer_mask_(buffer_size - 1)
64 | {
65 | // queue size must be power of two
66 | if (!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0)))
67 | {
68 | throw spdlog_ex("async logger queue size must be power of two");
69 | }
70 |
71 | for (size_t i = 0; i != buffer_size; i += 1)
72 | {
73 | buffer_[i].sequence_.store(i, std::memory_order_relaxed);
74 | }
75 | enqueue_pos_.store(0, std::memory_order_relaxed);
76 | dequeue_pos_.store(0, std::memory_order_relaxed);
77 | }
78 |
79 | ~mpmc_bounded_queue()
80 | {
81 | delete[] buffer_;
82 | }
83 |
84 | mpmc_bounded_queue(mpmc_bounded_queue const &) = delete;
85 | void operator=(mpmc_bounded_queue const &) = delete;
86 |
87 | bool enqueue(T &&data)
88 | {
89 | cell_t *cell;
90 | size_t pos = enqueue_pos_.load(std::memory_order_relaxed);
91 | for (;;)
92 | {
93 | cell = &buffer_[pos & buffer_mask_];
94 | size_t seq = cell->sequence_.load(std::memory_order_acquire);
95 | intptr_t dif = static_cast(seq) - static_cast(pos);
96 | if (dif == 0)
97 | {
98 | if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
99 | {
100 | break;
101 | }
102 | }
103 | else if (dif < 0)
104 | {
105 | return false;
106 | }
107 | else
108 | {
109 | pos = enqueue_pos_.load(std::memory_order_relaxed);
110 | }
111 | }
112 | cell->data_ = std::move(data);
113 | cell->sequence_.store(pos + 1, std::memory_order_release);
114 | return true;
115 | }
116 |
117 | bool dequeue(T &data)
118 | {
119 | cell_t *cell;
120 | size_t pos = dequeue_pos_.load(std::memory_order_relaxed);
121 | for (;;)
122 | {
123 | cell = &buffer_[pos & buffer_mask_];
124 | size_t seq = cell->sequence_.load(std::memory_order_acquire);
125 | intptr_t dif = static_cast(seq) - static_cast(pos + 1);
126 | if (dif == 0)
127 | {
128 | if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
129 | {
130 | break;
131 | }
132 | }
133 | else if (dif < 0)
134 | {
135 | return false;
136 | }
137 | else
138 | {
139 | pos = dequeue_pos_.load(std::memory_order_relaxed);
140 | }
141 | }
142 | data = std::move(cell->data_);
143 | cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release);
144 | return true;
145 | }
146 |
147 | bool is_empty()
148 | {
149 | size_t front, front1, back;
150 | // try to take a consistent snapshot of front/tail.
151 | do
152 | {
153 | front = enqueue_pos_.load(std::memory_order_acquire);
154 | back = dequeue_pos_.load(std::memory_order_acquire);
155 | front1 = enqueue_pos_.load(std::memory_order_relaxed);
156 | } while (front != front1);
157 | return back == front;
158 | }
159 |
160 | private:
161 | struct cell_t
162 | {
163 | std::atomic sequence_;
164 | T data_;
165 | };
166 |
167 | size_t const max_size_;
168 |
169 | static size_t const cacheline_size = 64;
170 | using cacheline_pad_t = char[cacheline_size];
171 |
172 | cacheline_pad_t pad0_;
173 | cell_t *const buffer_;
174 | size_t const buffer_mask_;
175 | cacheline_pad_t pad1_;
176 | std::atomic enqueue_pos_;
177 | cacheline_pad_t pad2_;
178 | std::atomic dequeue_pos_;
179 | cacheline_pad_t pad3_;
180 | };
181 |
182 | } // namespace details
183 | } // namespace spdlog
184 |
--------------------------------------------------------------------------------
/include/spdlog/details/null_mutex.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright(c) 2015 Gabi Melman.
3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
4 | //
5 |
6 | #pragma once
7 |
8 | #include
9 | // null, no cost dummy "mutex" and dummy "atomic" int
10 |
11 | namespace spdlog {
12 | namespace details {
13 | struct null_mutex
14 | {
15 | void lock() {}
16 | void unlock() {}
17 | bool try_lock()
18 | {
19 | return true;
20 | }
21 | };
22 |
23 | struct null_atomic_int
24 | {
25 | int value;
26 | null_atomic_int() = default;
27 |
28 | explicit null_atomic_int(int val)
29 | : value(val)
30 | {
31 | }
32 |
33 | int load(std::memory_order) const
34 | {
35 | return value;
36 | }
37 |
38 | void store(int val)
39 | {
40 | value = val;
41 | }
42 | };
43 |
44 | } // namespace details
45 | } // namespace spdlog
46 |
--------------------------------------------------------------------------------
/include/spdlog/fmt/bundled/LICENSE.rst:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012 - 2016, Victor Zverovich
2 |
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
--------------------------------------------------------------------------------
/include/spdlog/fmt/bundled/ostream.cc:
--------------------------------------------------------------------------------
1 | /*
2 | Formatting library for C++ - std::ostream support
3 |
4 | Copyright (c) 2012 - 2016, Victor Zverovich
5 | All rights reserved.
6 |
7 | For the license information refer to format.h.
8 | */
9 |
10 | #include "ostream.h"
11 |
12 | namespace fmt {
13 |
14 | namespace internal {
15 | FMT_FUNC void write(std::ostream &os, Writer &w) {
16 | const char *data = w.data();
17 | typedef internal::MakeUnsigned::Type UnsignedStreamSize;
18 | UnsignedStreamSize size = w.size();
19 | UnsignedStreamSize max_size =
20 | internal::to_unsigned((std::numeric_limits::max)());
21 | do {
22 | UnsignedStreamSize n = size <= max_size ? size : max_size;
23 | os.write(data, static_cast(n));
24 | data += n;
25 | size -= n;
26 | } while (size != 0);
27 | }
28 | }
29 |
30 | FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) {
31 | MemoryWriter w;
32 | w.write(format_str, args);
33 | internal::write(os, w);
34 | }
35 | } // namespace fmt
36 |
--------------------------------------------------------------------------------
/include/spdlog/fmt/bundled/ostream.h:
--------------------------------------------------------------------------------
1 | /*
2 | Formatting library for C++ - std::ostream support
3 |
4 | Copyright (c) 2012 - 2016, Victor Zverovich
5 | All rights reserved.
6 |
7 | For the license information refer to format.h.
8 | */
9 |
10 | #ifndef FMT_OSTREAM_H_
11 | #define FMT_OSTREAM_H_
12 |
13 | #include "format.h"
14 | #include
15 |
16 | namespace fmt {
17 |
18 | namespace internal {
19 |
20 | template
21 | class FormatBuf : public std::basic_streambuf
22 | {
23 | private:
24 | typedef typename std::basic_streambuf::int_type int_type;
25 | typedef typename std::basic_streambuf::traits_type traits_type;
26 |
27 | Buffer &buffer_;
28 |
29 | public:
30 | FormatBuf(Buffer &buffer)
31 | : buffer_(buffer)
32 | {
33 | }
34 |
35 | protected:
36 | // The put-area is actually always empty. This makes the implementation
37 | // simpler and has the advantage that the streambuf and the buffer are always
38 | // in sync and sputc never writes into uninitialized memory. The obvious
39 | // disadvantage is that each call to sputc always results in a (virtual) call
40 | // to overflow. There is no disadvantage here for sputn since this always
41 | // results in a call to xsputn.
42 |
43 | int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE
44 | {
45 | if (!traits_type::eq_int_type(ch, traits_type::eof()))
46 | buffer_.push_back(static_cast(ch));
47 | return ch;
48 | }
49 |
50 | std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE
51 | {
52 | buffer_.append(s, s + count);
53 | return count;
54 | }
55 | };
56 |
57 | Yes &convert(std::ostream &);
58 |
59 | struct DummyStream : std::ostream
60 | {
61 | DummyStream(); // Suppress a bogus warning in MSVC.
62 |
63 | // Hide all operator<< overloads from std::ostream.
64 | template
65 | typename EnableIf::type operator<<(const T &);
66 | };
67 |
68 | No &operator<<(std::ostream &, int);
69 |
70 | template
71 | struct ConvertToIntImpl
72 | {
73 | // Convert to int only if T doesn't have an overloaded operator<<.
74 | enum
75 | {
76 | value = sizeof(convert(get() << get())) == sizeof(No)
77 | };
78 | };
79 |
80 | // Write the content of w to os.
81 | FMT_API void write(std::ostream &os, Writer &w);
82 | } // namespace internal
83 |
84 | // Formats a value.
85 | template
86 | void format_arg(BasicFormatter &f, const Char *&format_str, const T &value)
87 | {
88 | internal::MemoryBuffer buffer;
89 |
90 | internal::FormatBuf format_buf(buffer);
91 | std::basic_ostream output(&format_buf);
92 | output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
93 | output << value;
94 |
95 | BasicStringRef str(&buffer[0], buffer.size());
96 | typedef internal::MakeArg> MakeArg;
97 | format_str = f.format(format_str, MakeArg(str));
98 | }
99 |
100 | /**
101 | \rst
102 | Prints formatted data to the stream *os*.
103 |
104 | **Example**::
105 |
106 | print(cerr, "Don't {}!", "panic");
107 | \endrst
108 | */
109 | FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
110 | FMT_VARIADIC(void, print, std::ostream &, CStringRef)
111 | } // namespace fmt
112 |
113 | #ifdef FMT_HEADER_ONLY
114 | #include "ostream.cc"
115 | #endif
116 |
117 | #endif // FMT_OSTREAM_H_
118 |
--------------------------------------------------------------------------------
/include/spdlog/fmt/bundled/printf.cc:
--------------------------------------------------------------------------------
1 | /*
2 | Formatting library for C++
3 |
4 | Copyright (c) 2012 - 2016, Victor Zverovich
5 | All rights reserved.
6 |
7 | For the license information refer to format.h.
8 | */
9 |
10 | #include "format.h"
11 | #include "printf.h"
12 |
13 | namespace fmt {
14 |
15 | template
16 | void printf(BasicWriter &w, BasicCStringRef format, ArgList args);
17 |
18 | FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args) {
19 | MemoryWriter w;
20 | printf(w, format, args);
21 | std::size_t size = w.size();
22 | return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast(size);
23 | }
24 |
25 | #ifndef FMT_HEADER_ONLY
26 |
27 | template void PrintfFormatter::format(CStringRef format);
28 | template void PrintfFormatter::format(WCStringRef format);
29 |
30 | #endif // FMT_HEADER_ONLY
31 |
32 | } // namespace fmt
33 |
--------------------------------------------------------------------------------
/include/spdlog/fmt/bundled/time.h:
--------------------------------------------------------------------------------
1 | /*
2 | Formatting library for C++ - time formatting
3 |
4 | Copyright (c) 2012 - 2016, Victor Zverovich
5 | All rights reserved.
6 |
7 | For the license information refer to format.h.
8 | */
9 |
10 | #ifndef FMT_TIME_H_
11 | #define FMT_TIME_H_
12 |
13 | #include "format.h"
14 | #include
15 |
16 | #ifdef _MSC_VER
17 | #pragma warning(push)
18 | #pragma warning(disable : 4702) // unreachable code
19 | #pragma warning(disable : 4996) // "deprecated" functions
20 | #endif
21 |
22 | namespace fmt {
23 | template
24 | void format_arg(BasicFormatter &f, const char *&format_str, const std::tm &tm)
25 | {
26 | if (*format_str == ':')
27 | ++format_str;
28 | const char *end = format_str;
29 | while (*end && *end != '}')
30 | ++end;
31 | if (*end != '}')
32 | FMT_THROW(FormatError("missing '}' in format string"));
33 | internal::MemoryBuffer format;
34 | format.append(format_str, end + 1);
35 | format[format.size() - 1] = '\0';
36 | Buffer &buffer = f.writer().buffer();
37 | std::size_t start = buffer.size();
38 | for (;;)
39 | {
40 | std::size_t size = buffer.capacity() - start;
41 | std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm);
42 | if (count != 0)
43 | {
44 | buffer.resize(start + count);
45 | break;
46 | }
47 | if (size >= format.size() * 256)
48 | {
49 | // If the buffer is 256 times larger than the format string, assume
50 | // that `strftime` gives an empty result. There doesn't seem to be a
51 | // better way to distinguish the two cases:
52 | // https://github.com/fmtlib/fmt/issues/367
53 | break;
54 | }
55 | const std::size_t MIN_GROWTH = 10;
56 | buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
57 | }
58 | format_str = end + 1;
59 | }
60 |
61 | namespace internal {
62 | inline Null<> localtime_r(...)
63 | {
64 | return Null<>();
65 | }
66 | inline Null<> localtime_s(...)
67 | {
68 | return Null<>();
69 | }
70 | inline Null<> gmtime_r(...)
71 | {
72 | return Null<>();
73 | }
74 | inline Null<> gmtime_s(...)
75 | {
76 | return Null<>();
77 | }
78 | } // namespace internal
79 |
80 | // Thread-safe replacement for std::localtime
81 | inline std::tm localtime(std::time_t time)
82 | {
83 | struct LocalTime
84 | {
85 | std::time_t time_;
86 | std::tm tm_;
87 |
88 | LocalTime(std::time_t t)
89 | : time_(t)
90 | {
91 | }
92 |
93 | bool run()
94 | {
95 | using namespace fmt::internal;
96 | return handle(localtime_r(&time_, &tm_));
97 | }
98 |
99 | bool handle(std::tm *tm)
100 | {
101 | return tm != FMT_NULL;
102 | }
103 |
104 | bool handle(internal::Null<>)
105 | {
106 | using namespace fmt::internal;
107 | return fallback(localtime_s(&tm_, &time_));
108 | }
109 |
110 | bool fallback(int res)
111 | {
112 | return res == 0;
113 | }
114 |
115 | bool fallback(internal::Null<>)
116 | {
117 | using namespace fmt::internal;
118 | std::tm *tm = std::localtime(&time_);
119 | if (tm)
120 | tm_ = *tm;
121 | return tm != FMT_NULL;
122 | }
123 | };
124 | LocalTime lt(time);
125 | if (lt.run())
126 | return lt.tm_;
127 | // Too big time values may be unsupported.
128 | FMT_THROW(fmt::FormatError("time_t value out of range"));
129 | return std::tm();
130 | }
131 |
132 | // Thread-safe replacement for std::gmtime
133 | inline std::tm gmtime(std::time_t time)
134 | {
135 | struct GMTime
136 | {
137 | std::time_t time_;
138 | std::tm tm_;
139 |
140 | GMTime(std::time_t t)
141 | : time_(t)
142 | {
143 | }
144 |
145 | bool run()
146 | {
147 | using namespace fmt::internal;
148 | return handle(gmtime_r(&time_, &tm_));
149 | }
150 |
151 | bool handle(std::tm *tm)
152 | {
153 | return tm != FMT_NULL;
154 | }
155 |
156 | bool handle(internal::Null<>)
157 | {
158 | using namespace fmt::internal;
159 | return fallback(gmtime_s(&tm_, &time_));
160 | }
161 |
162 | bool fallback(int res)
163 | {
164 | return res == 0;
165 | }
166 |
167 | bool fallback(internal::Null<>)
168 | {
169 | std::tm *tm = std::gmtime(&time_);
170 | if (tm != FMT_NULL)
171 | tm_ = *tm;
172 | return tm != FMT_NULL;
173 | }
174 | };
175 | GMTime gt(time);
176 | if (gt.run())
177 | return gt.tm_;
178 | // Too big time values may be unsupported.
179 | FMT_THROW(fmt::FormatError("time_t value out of range"));
180 | return std::tm();
181 | }
182 | } // namespace fmt
183 |
184 | #ifdef _MSC_VER
185 | #pragma warning(pop)
186 | #endif
187 |
188 | #endif // FMT_TIME_H_
189 |
--------------------------------------------------------------------------------
/include/spdlog/fmt/fmt.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright(c) 2016 Gabi Melman.
3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
4 | //
5 |
6 | #pragma once
7 |
8 | //
9 | // Include a bundled header-only copy of fmtlib or an external one.
10 | // By default spdlog include its own copy.
11 | //
12 |
13 | #if !defined(SPDLOG_FMT_EXTERNAL)
14 |
15 | #ifndef FMT_HEADER_ONLY
16 | #define FMT_HEADER_ONLY
17 | #endif
18 | #ifndef FMT_USE_WINDOWS_H
19 | #define FMT_USE_WINDOWS_H 0
20 | #endif
21 | #include "bundled/format.h"
22 | #if defined(SPDLOG_FMT_PRINTF)
23 | #include "bundled/printf.h"
24 | #endif
25 |
26 | #else // external fmtlib
27 |
28 | #include
29 | #if defined(SPDLOG_FMT_PRINTF)
30 | #include
31 | #endif
32 |
33 | #endif
34 |
--------------------------------------------------------------------------------
/include/spdlog/fmt/ostr.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright(c) 2016 Gabi Melman.
3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
4 | //
5 |
6 | #pragma once
7 | //
8 | // include bundled or external copy of fmtlib's ostream support
9 | //
10 | #if !defined(SPDLOG_FMT_EXTERNAL)
11 | #ifndef FMT_HEADER_ONLY
12 | #define FMT_HEADER_ONLY
13 | #endif
14 | #include "bundled/ostream.h"
15 | #include "fmt.h"
16 | #else
17 | #include
18 | #endif
19 |
--------------------------------------------------------------------------------
/include/spdlog/formatter.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright(c) 2015 Gabi Melman.
3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
4 | //
5 |
6 | #pragma once
7 |
8 | #include "details/log_msg.h"
9 |
10 | #include
11 | #include
12 | #include
13 |
14 | namespace spdlog {
15 | namespace details {
16 | class flag_formatter;
17 | }
18 |
19 | class formatter
20 | {
21 | public:
22 | virtual ~formatter() = default;
23 | virtual void format(details::log_msg &msg) = 0;
24 | };
25 |
26 | class pattern_formatter SPDLOG_FINAL : public formatter
27 | {
28 | public:
29 | explicit pattern_formatter(const std::string &pattern, pattern_time_type pattern_time = pattern_time_type::local,
30 | std::string eol = spdlog::details::os::default_eol);
31 | pattern_formatter(const pattern_formatter &) = delete;
32 | pattern_formatter &operator=(const pattern_formatter &) = delete;
33 | void format(details::log_msg &msg) override;
34 |
35 | private:
36 | const std::string _eol;
37 | const std::string _pattern;
38 | const pattern_time_type _pattern_time;
39 | std::vector> _formatters;
40 | std::tm get_time(details::log_msg &msg);
41 | void handle_flag(char flag);
42 | void compile_pattern(const std::string &pattern);
43 | };
44 | } // namespace spdlog
45 |
46 | #include "details/pattern_formatter_impl.h"
47 |
--------------------------------------------------------------------------------
/include/spdlog/logger.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright(c) 2015 Gabi Melman.
3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT)
4 | //
5 |
6 | #pragma once
7 |
8 | // Thread safe logger (except for set_pattern(..), set_formatter(..) and set_error_handler())
9 | // Has name, log level, vector of std::shared sink pointers and formatter
10 | // Upon each log write the logger:
11 | // 1. Checks if its log level is enough to log the message
12 | // 2. Format the message using the formatter function
13 | // 3. Pass the formatted message to its sinks to performa the actual logging
14 |
15 | #include "common.h"
16 | #include "sinks/base_sink.h"
17 |
18 | #include
19 | #include
20 | #include
21 |
22 | namespace spdlog {
23 |
24 | class logger
25 | {
26 | public:
27 | logger(const std::string &name, sink_ptr single_sink);
28 | logger(const std::string &name, sinks_init_list sinks);
29 |
30 | template
31 | logger(std::string name, const It &begin, const It &end);
32 |
33 | virtual ~logger();
34 |
35 | logger(const logger &) = delete;
36 | logger &operator=(const logger &) = delete;
37 |
38 | template
39 | void log(level::level_enum lvl, const char *fmt, const Args &... args);
40 |
41 | template
42 | void log(level::level_enum lvl, const char *msg);
43 |
44 | template
45 | void trace(const char *fmt, const Arg1 &, const Args &... args);
46 |
47 | template
48 | void debug(const char *fmt, const Arg1 &, const Args &... args);
49 |
50 | template
51 | void info(const char *fmt, const Arg1 &, const Args &... args);
52 |
53 | template
54 | void warn(const char *fmt, const Arg1 &, const Args &... args);
55 |
56 | template
57 | void error(const char *fmt, const Arg1 &, const Args &... args);
58 |
59 | template
60 | void critical(const char *fmt, const Arg1 &, const Args &... args);
61 |
62 | #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
63 | template
64 | void log(level::level_enum lvl, const wchar_t *msg);
65 |
66 | template
67 | void log(level::level_enum lvl, const wchar_t *fmt, const Args &... args);
68 |
69 | template
70 | void trace(const wchar_t *fmt, const Args &... args);
71 |
72 | template
73 | void debug(const wchar_t *fmt, const Args &... args);
74 |
75 | template
76 | void info(const wchar_t *fmt, const Args &... args);
77 |
78 | template
79 | void warn(const wchar_t *fmt, const Args &... args);
80 |
81 | template
82 | void error(const wchar_t *fmt, const Args &... args);
83 |
84 | template
85 | void critical(const wchar_t *fmt, const Args &... args);
86 | #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
87 |
88 | template
89 | void log(level::level_enum lvl, const T &);
90 |
91 | template
92 | void trace(const T &msg);
93 |
94 | template
95 | void debug(const T &msg);
96 |
97 | template
98 | void info(const T &msg);
99 |
100 | template
101 | void warn(const T &msg);
102 |
103 | template