├── .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 | [![Build Status](https://travis-ci.org/prideout/lava.svg?branch=master)](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 104 | void error(const T &msg); 105 | 106 | template 107 | void critical(const T &msg); 108 | 109 | bool should_log(level::level_enum msg_level) const; 110 | void set_level(level::level_enum log_level); 111 | level::level_enum level() const; 112 | const std::string &name() const; 113 | void set_pattern(const std::string &pattern, pattern_time_type pattern_time = pattern_time_type::local); 114 | void set_formatter(formatter_ptr msg_formatter); 115 | 116 | // automatically call flush() if message level >= log_level 117 | void flush_on(level::level_enum log_level); 118 | 119 | virtual void flush(); 120 | 121 | const std::vector &sinks() const; 122 | 123 | // error handler 124 | virtual void set_error_handler(log_err_handler err_handler); 125 | virtual log_err_handler error_handler(); 126 | 127 | protected: 128 | virtual void _sink_it(details::log_msg &msg); 129 | virtual void _set_pattern(const std::string &pattern, pattern_time_type pattern_time); 130 | virtual void _set_formatter(formatter_ptr msg_formatter); 131 | 132 | // default error handler: print the error to stderr with the max rate of 1 message/minute 133 | virtual void _default_err_handler(const std::string &msg); 134 | 135 | // return true if the given message level should trigger a flush 136 | bool _should_flush_on(const details::log_msg &msg); 137 | 138 | // increment the message count (only if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)) 139 | void _incr_msg_counter(details::log_msg &msg); 140 | 141 | const std::string _name; 142 | std::vector _sinks; 143 | formatter_ptr _formatter; 144 | spdlog::level_t _level; 145 | spdlog::level_t _flush_level; 146 | log_err_handler _err_handler; 147 | std::atomic _last_err_time; 148 | std::atomic _msg_counter; 149 | }; 150 | } // namespace spdlog 151 | 152 | #include "details/logger_impl.h" 153 | -------------------------------------------------------------------------------- /include/spdlog/sinks/android_sink.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 | #if defined(__ANDROID__) 9 | 10 | #include "../details/os.h" 11 | #include "sink.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #if !defined(SPDLOG_ANDROID_RETRIES) 20 | #define SPDLOG_ANDROID_RETRIES 2 21 | #endif 22 | 23 | namespace spdlog { 24 | namespace sinks { 25 | 26 | /* 27 | * Android sink (logging using __android_log_write) 28 | * __android_log_write is thread-safe. No lock is needed. 29 | */ 30 | class android_sink : public sink 31 | { 32 | public: 33 | explicit android_sink(const std::string &tag = "spdlog", bool use_raw_msg = false) 34 | : _tag(tag) 35 | , _use_raw_msg(use_raw_msg) 36 | { 37 | } 38 | 39 | void log(const details::log_msg &msg) override 40 | { 41 | const android_LogPriority priority = convert_to_android(msg.level); 42 | const char *msg_output = (_use_raw_msg ? msg.raw.c_str() : msg.formatted.c_str()); 43 | 44 | // See system/core/liblog/logger_write.c for explanation of return value 45 | int ret = __android_log_write(priority, _tag.c_str(), msg_output); 46 | int retry_count = 0; 47 | while ((ret == -11 /*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES)) 48 | { 49 | details::os::sleep_for_millis(5); 50 | ret = __android_log_write(priority, _tag.c_str(), msg_output); 51 | retry_count++; 52 | } 53 | 54 | if (ret < 0) 55 | { 56 | throw spdlog_ex("__android_log_write() failed", ret); 57 | } 58 | } 59 | 60 | void flush() override {} 61 | 62 | private: 63 | static android_LogPriority convert_to_android(spdlog::level::level_enum level) 64 | { 65 | switch (level) 66 | { 67 | case spdlog::level::trace: 68 | return ANDROID_LOG_VERBOSE; 69 | case spdlog::level::debug: 70 | return ANDROID_LOG_DEBUG; 71 | case spdlog::level::info: 72 | return ANDROID_LOG_INFO; 73 | case spdlog::level::warn: 74 | return ANDROID_LOG_WARN; 75 | case spdlog::level::err: 76 | return ANDROID_LOG_ERROR; 77 | case spdlog::level::critical: 78 | return ANDROID_LOG_FATAL; 79 | default: 80 | return ANDROID_LOG_DEFAULT; 81 | } 82 | } 83 | 84 | std::string _tag; 85 | bool _use_raw_msg; 86 | }; 87 | 88 | } // namespace sinks 89 | } // namespace spdlog 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /include/spdlog/sinks/ansicolor_sink.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2017 spdlog authors. 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 | #include "base_sink.h" 11 | 12 | #include 13 | #include 14 | 15 | namespace spdlog { 16 | namespace sinks { 17 | 18 | /** 19 | * This sink prefixes the output with an ANSI escape sequence color code depending on the severity 20 | * of the message. 21 | * If no color terminal detected, omit the escape codes. 22 | */ 23 | template 24 | class ansicolor_sink : public base_sink 25 | { 26 | public: 27 | explicit ansicolor_sink(FILE *file) 28 | : target_file_(file) 29 | { 30 | should_do_colors_ = details::os::in_terminal(file) && details::os::is_color_terminal(); 31 | colors_[level::trace] = white; 32 | colors_[level::debug] = cyan; 33 | colors_[level::info] = green; 34 | colors_[level::warn] = yellow + bold; 35 | colors_[level::err] = red + bold; 36 | colors_[level::critical] = bold + on_red; 37 | colors_[level::off] = reset; 38 | } 39 | 40 | ~ansicolor_sink() override 41 | { 42 | _flush(); 43 | } 44 | 45 | void set_color(level::level_enum color_level, const std::string &color) 46 | { 47 | std::lock_guard lock(base_sink::_mutex); 48 | colors_[color_level] = color; 49 | } 50 | 51 | /// Formatting codes 52 | const std::string reset = "\033[m"; 53 | const std::string bold = "\033[1m"; 54 | const std::string dark = "\033[2m"; 55 | const std::string underline = "\033[4m"; 56 | const std::string blink = "\033[5m"; 57 | const std::string reverse = "\033[7m"; 58 | const std::string concealed = "\033[8m"; 59 | const std::string clear_line = "\033[K"; 60 | 61 | // Foreground colors 62 | const std::string black = "\033[30m"; 63 | const std::string red = "\033[31m"; 64 | const std::string green = "\033[32m"; 65 | const std::string yellow = "\033[33m"; 66 | const std::string blue = "\033[34m"; 67 | const std::string magenta = "\033[35m"; 68 | const std::string cyan = "\033[36m"; 69 | const std::string white = "\033[37m"; 70 | 71 | /// Background colors 72 | const std::string on_black = "\033[40m"; 73 | const std::string on_red = "\033[41m"; 74 | const std::string on_green = "\033[42m"; 75 | const std::string on_yellow = "\033[43m"; 76 | const std::string on_blue = "\033[44m"; 77 | const std::string on_magenta = "\033[45m"; 78 | const std::string on_cyan = "\033[46m"; 79 | const std::string on_white = "\033[47m"; 80 | 81 | protected: 82 | void _sink_it(const details::log_msg &msg) override 83 | { 84 | // Wrap the originally formatted message in color codes. 85 | // If color is not supported in the terminal, log as is instead. 86 | if (should_do_colors_ && msg.color_range_end > msg.color_range_start) 87 | { 88 | // before color range 89 | _print_range(msg, 0, msg.color_range_start); 90 | // in color range 91 | _print_ccode(colors_[msg.level]); 92 | _print_range(msg, msg.color_range_start, msg.color_range_end); 93 | _print_ccode(reset); 94 | // after color range 95 | _print_range(msg, msg.color_range_end, msg.formatted.size()); 96 | } 97 | else 98 | { 99 | _print_range(msg, 0, msg.formatted.size()); 100 | } 101 | _flush(); 102 | } 103 | 104 | void _flush() override 105 | { 106 | fflush(target_file_); 107 | } 108 | 109 | private: 110 | void _print_ccode(const std::string &color_code) 111 | { 112 | fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_); 113 | } 114 | void _print_range(const details::log_msg &msg, size_t start, size_t end) 115 | { 116 | fwrite(msg.formatted.data() + start, sizeof(char), end - start, target_file_); 117 | } 118 | FILE *target_file_; 119 | bool should_do_colors_; 120 | std::unordered_map colors_; 121 | }; 122 | 123 | template 124 | class ansicolor_stdout_sink : public ansicolor_sink 125 | { 126 | public: 127 | ansicolor_stdout_sink() 128 | : ansicolor_sink(stdout) 129 | { 130 | } 131 | }; 132 | 133 | using ansicolor_stdout_sink_mt = ansicolor_stdout_sink; 134 | using ansicolor_stdout_sink_st = ansicolor_stdout_sink; 135 | 136 | template 137 | class ansicolor_stderr_sink : public ansicolor_sink 138 | { 139 | public: 140 | ansicolor_stderr_sink() 141 | : ansicolor_sink(stderr) 142 | { 143 | } 144 | }; 145 | 146 | using ansicolor_stderr_sink_mt = ansicolor_stderr_sink; 147 | using ansicolor_stderr_sink_st = ansicolor_stderr_sink; 148 | 149 | } // namespace sinks 150 | } // namespace spdlog 151 | -------------------------------------------------------------------------------- /include/spdlog/sinks/base_sink.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 | // base sink templated over a mutex (either dummy or real) 9 | // concrete implementation should only override the _sink_it method. 10 | // all locking is taken care of here so no locking needed by the implementers.. 11 | // 12 | 13 | #include "../common.h" 14 | #include "../details/log_msg.h" 15 | #include "../formatter.h" 16 | #include "sink.h" 17 | 18 | #include 19 | 20 | namespace spdlog { 21 | namespace sinks { 22 | template 23 | class base_sink : public sink 24 | { 25 | public: 26 | base_sink() = default; 27 | 28 | base_sink(const base_sink &) = delete; 29 | base_sink &operator=(const base_sink &) = delete; 30 | 31 | void log(const details::log_msg &msg) SPDLOG_FINAL override 32 | { 33 | std::lock_guard lock(_mutex); 34 | _sink_it(msg); 35 | } 36 | 37 | void flush() SPDLOG_FINAL override 38 | { 39 | std::lock_guard lock(_mutex); 40 | _flush(); 41 | } 42 | 43 | protected: 44 | virtual void _sink_it(const details::log_msg &msg) = 0; 45 | virtual void _flush() = 0; 46 | Mutex _mutex; 47 | }; 48 | } // namespace sinks 49 | } // namespace spdlog 50 | -------------------------------------------------------------------------------- /include/spdlog/sinks/dist_sink.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015 David Schury, 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 | #include "../details/null_mutex.h" 10 | #include "base_sink.h" 11 | #include "sink.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | // Distribution sink (mux). Stores a vector of sinks which get called when log is called 19 | 20 | namespace spdlog { 21 | namespace sinks { 22 | template 23 | class dist_sink : public base_sink 24 | { 25 | public: 26 | explicit dist_sink() 27 | : _sinks() 28 | { 29 | } 30 | dist_sink(const dist_sink &) = delete; 31 | dist_sink &operator=(const dist_sink &) = delete; 32 | 33 | protected: 34 | std::vector> _sinks; 35 | 36 | void _sink_it(const details::log_msg &msg) override 37 | { 38 | for (auto &sink : _sinks) 39 | { 40 | if (sink->should_log(msg.level)) 41 | { 42 | sink->log(msg); 43 | } 44 | } 45 | } 46 | 47 | void _flush() override 48 | { 49 | for (auto &sink : _sinks) 50 | sink->flush(); 51 | } 52 | 53 | public: 54 | void add_sink(std::shared_ptr sink) 55 | { 56 | std::lock_guard lock(base_sink::_mutex); 57 | _sinks.push_back(sink); 58 | } 59 | 60 | void remove_sink(std::shared_ptr sink) 61 | { 62 | std::lock_guard lock(base_sink::_mutex); 63 | _sinks.erase(std::remove(_sinks.begin(), _sinks.end(), sink), _sinks.end()); 64 | } 65 | }; 66 | 67 | using dist_sink_mt = dist_sink; 68 | using dist_sink_st = dist_sink; 69 | 70 | } // namespace sinks 71 | } // namespace spdlog 72 | -------------------------------------------------------------------------------- /include/spdlog/sinks/msvc_sink.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 Alexander Dalshov. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | 8 | #if defined(_WIN32) 9 | 10 | #include "../details/null_mutex.h" 11 | #include "base_sink.h" 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | namespace spdlog { 19 | namespace sinks { 20 | /* 21 | * MSVC sink (logging using OutputDebugStringA) 22 | */ 23 | template 24 | class msvc_sink : public base_sink 25 | { 26 | public: 27 | explicit msvc_sink() {} 28 | 29 | protected: 30 | void _sink_it(const details::log_msg &msg) override 31 | { 32 | OutputDebugStringA(msg.formatted.c_str()); 33 | } 34 | 35 | void _flush() override {} 36 | }; 37 | 38 | using msvc_sink_mt = msvc_sink; 39 | using msvc_sink_st = msvc_sink; 40 | 41 | } // namespace sinks 42 | } // namespace spdlog 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /include/spdlog/sinks/null_sink.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/null_mutex.h" 9 | #include "base_sink.h" 10 | 11 | #include 12 | 13 | namespace spdlog { 14 | namespace sinks { 15 | 16 | template 17 | class null_sink : public base_sink 18 | { 19 | protected: 20 | void _sink_it(const details::log_msg &) override {} 21 | 22 | void _flush() override {} 23 | }; 24 | 25 | using null_sink_mt = null_sink; 26 | using null_sink_st = null_sink; 27 | 28 | } // namespace sinks 29 | } // namespace spdlog 30 | -------------------------------------------------------------------------------- /include/spdlog/sinks/ostream_sink.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/null_mutex.h" 9 | #include "base_sink.h" 10 | 11 | #include 12 | #include 13 | 14 | namespace spdlog { 15 | namespace sinks { 16 | template 17 | class ostream_sink : public base_sink 18 | { 19 | public: 20 | explicit ostream_sink(std::ostream &os, bool force_flush = false) 21 | : _ostream(os) 22 | , _force_flush(force_flush) 23 | { 24 | } 25 | ostream_sink(const ostream_sink &) = delete; 26 | ostream_sink &operator=(const ostream_sink &) = delete; 27 | 28 | protected: 29 | void _sink_it(const details::log_msg &msg) override 30 | { 31 | _ostream.write(msg.formatted.data(), msg.formatted.size()); 32 | if (_force_flush) 33 | _ostream.flush(); 34 | } 35 | 36 | void _flush() override 37 | { 38 | _ostream.flush(); 39 | } 40 | 41 | std::ostream &_ostream; 42 | bool _force_flush; 43 | }; 44 | 45 | using ostream_sink_mt = ostream_sink; 46 | using ostream_sink_st = ostream_sink; 47 | 48 | } // namespace sinks 49 | } // namespace spdlog 50 | -------------------------------------------------------------------------------- /include/spdlog/sinks/sink.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 | namespace spdlog { 11 | namespace sinks { 12 | class sink 13 | { 14 | public: 15 | virtual ~sink() = default; 16 | 17 | virtual void log(const details::log_msg &msg) = 0; 18 | virtual void flush() = 0; 19 | 20 | bool should_log(level::level_enum msg_level) const; 21 | void set_level(level::level_enum log_level); 22 | level::level_enum level() const; 23 | 24 | private: 25 | level_t _level{level::trace}; 26 | }; 27 | 28 | inline bool sink::should_log(level::level_enum msg_level) const 29 | { 30 | return msg_level >= _level.load(std::memory_order_relaxed); 31 | } 32 | 33 | inline void sink::set_level(level::level_enum log_level) 34 | { 35 | _level.store(log_level); 36 | } 37 | 38 | inline level::level_enum sink::level() const 39 | { 40 | return static_cast(_level.load(std::memory_order_relaxed)); 41 | } 42 | 43 | } // namespace sinks 44 | } // namespace spdlog 45 | -------------------------------------------------------------------------------- /include/spdlog/sinks/stdout_sinks.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/null_mutex.h" 9 | #include "base_sink.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace spdlog { 16 | namespace sinks { 17 | 18 | template 19 | class stdout_sink SPDLOG_FINAL : public base_sink 20 | { 21 | using MyType = stdout_sink; 22 | 23 | public: 24 | explicit stdout_sink() = default; 25 | 26 | static std::shared_ptr instance() 27 | { 28 | static std::shared_ptr instance = std::make_shared(); 29 | return instance; 30 | } 31 | 32 | protected: 33 | void _sink_it(const details::log_msg &msg) override 34 | { 35 | fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stdout); 36 | _flush(); 37 | } 38 | 39 | void _flush() override 40 | { 41 | fflush(stdout); 42 | } 43 | }; 44 | 45 | using stdout_sink_mt = stdout_sink; 46 | using stdout_sink_st = stdout_sink; 47 | 48 | template 49 | class stderr_sink SPDLOG_FINAL : public base_sink 50 | { 51 | using MyType = stderr_sink; 52 | 53 | public: 54 | explicit stderr_sink() = default; 55 | 56 | static std::shared_ptr instance() 57 | { 58 | static std::shared_ptr instance = std::make_shared(); 59 | return instance; 60 | } 61 | 62 | protected: 63 | void _sink_it(const details::log_msg &msg) override 64 | { 65 | fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stderr); 66 | _flush(); 67 | } 68 | 69 | void _flush() override 70 | { 71 | fflush(stderr); 72 | } 73 | }; 74 | 75 | using stderr_sink_mt = stderr_sink; 76 | using stderr_sink_st = stderr_sink; 77 | 78 | } // namespace sinks 79 | } // namespace spdlog 80 | -------------------------------------------------------------------------------- /include/spdlog/sinks/syslog_sink.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 | 10 | #ifdef SPDLOG_ENABLE_SYSLOG 11 | 12 | #include "../details/log_msg.h" 13 | #include "sink.h" 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | namespace spdlog { 20 | namespace sinks { 21 | /** 22 | * Sink that write to syslog using the `syscall()` library call. 23 | * 24 | * Locking is not needed, as `syslog()` itself is thread-safe. 25 | */ 26 | class syslog_sink : public sink 27 | { 28 | public: 29 | // 30 | syslog_sink(const std::string &ident = "", int syslog_option = 0, int syslog_facility = LOG_USER) 31 | : _ident(ident) 32 | { 33 | _priorities[static_cast(level::trace)] = LOG_DEBUG; 34 | _priorities[static_cast(level::debug)] = LOG_DEBUG; 35 | _priorities[static_cast(level::info)] = LOG_INFO; 36 | _priorities[static_cast(level::warn)] = LOG_WARNING; 37 | _priorities[static_cast(level::err)] = LOG_ERR; 38 | _priorities[static_cast(level::critical)] = LOG_CRIT; 39 | _priorities[static_cast(level::off)] = LOG_INFO; 40 | 41 | // set ident to be program name if empty 42 | ::openlog(_ident.empty() ? nullptr : _ident.c_str(), syslog_option, syslog_facility); 43 | } 44 | 45 | ~syslog_sink() override 46 | { 47 | ::closelog(); 48 | } 49 | 50 | syslog_sink(const syslog_sink &) = delete; 51 | syslog_sink &operator=(const syslog_sink &) = delete; 52 | 53 | void log(const details::log_msg &msg) override 54 | { 55 | ::syslog(syslog_prio_from_level(msg), "%s", msg.raw.str().c_str()); 56 | } 57 | 58 | void flush() override {} 59 | 60 | private: 61 | std::array _priorities; 62 | // must store the ident because the man says openlog might use the pointer as is and not a string copy 63 | const std::string _ident; 64 | 65 | // 66 | // Simply maps spdlog's log level to syslog priority level. 67 | // 68 | int syslog_prio_from_level(const details::log_msg &msg) const 69 | { 70 | return _priorities[static_cast(msg.level)]; 71 | } 72 | }; 73 | } // namespace sinks 74 | } // namespace spdlog 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /include/spdlog/sinks/wincolor_sink.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2016 spdlog 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | 8 | #include "../common.h" 9 | #include "../details/null_mutex.h" 10 | #include "base_sink.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace spdlog { 18 | namespace sinks { 19 | /* 20 | * Windows color console sink. Uses WriteConsoleA to write to the console with colors 21 | */ 22 | template 23 | class wincolor_sink : public base_sink 24 | { 25 | public: 26 | const WORD BOLD = FOREGROUND_INTENSITY; 27 | const WORD RED = FOREGROUND_RED; 28 | const WORD GREEN = FOREGROUND_GREEN; 29 | const WORD CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE; 30 | const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; 31 | const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN; 32 | 33 | wincolor_sink(HANDLE std_handle) 34 | : out_handle_(std_handle) 35 | { 36 | colors_[level::trace] = WHITE; 37 | colors_[level::debug] = CYAN; 38 | colors_[level::info] = GREEN; 39 | colors_[level::warn] = YELLOW | BOLD; 40 | colors_[level::err] = RED | BOLD; // red bold 41 | colors_[level::critical] = BACKGROUND_RED | WHITE | BOLD; // white bold on red background 42 | colors_[level::off] = 0; 43 | } 44 | 45 | ~wincolor_sink() override 46 | { 47 | this->flush(); 48 | } 49 | 50 | wincolor_sink(const wincolor_sink &other) = delete; 51 | wincolor_sink &operator=(const wincolor_sink &other) = delete; 52 | 53 | // change the color for the given level 54 | void set_color(level::level_enum level, WORD color) 55 | { 56 | std::lock_guard lock(base_sink::_mutex); 57 | colors_[level] = color; 58 | } 59 | 60 | protected: 61 | void _sink_it(const details::log_msg &msg) override 62 | { 63 | if (msg.color_range_end > msg.color_range_start) 64 | { 65 | // before color range 66 | _print_range(msg, 0, msg.color_range_start); 67 | 68 | // in color range 69 | auto orig_attribs = set_console_attribs(colors_[msg.level]); 70 | _print_range(msg, msg.color_range_start, msg.color_range_end); 71 | ::SetConsoleTextAttribute(out_handle_, orig_attribs); // reset to orig colors 72 | // after color range 73 | _print_range(msg, msg.color_range_end, msg.formatted.size()); 74 | } 75 | else // print without colors if color range is invalid 76 | { 77 | _print_range(msg, 0, msg.formatted.size()); 78 | } 79 | } 80 | 81 | void _flush() override 82 | { 83 | // windows console always flushed? 84 | } 85 | 86 | private: 87 | HANDLE out_handle_; 88 | std::unordered_map colors_; 89 | 90 | // set color and return the orig console attributes (for resetting later) 91 | WORD set_console_attribs(WORD attribs) 92 | { 93 | CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info; 94 | GetConsoleScreenBufferInfo(out_handle_, &orig_buffer_info); 95 | WORD back_color = orig_buffer_info.wAttributes; 96 | // retrieve the current background color 97 | back_color &= static_cast(~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY)); 98 | // keep the background color unchanged 99 | SetConsoleTextAttribute(out_handle_, attribs | back_color); 100 | return orig_buffer_info.wAttributes; // return orig attribs 101 | } 102 | 103 | // print a range of formatted message to console 104 | void _print_range(const details::log_msg &msg, size_t start, size_t end) 105 | { 106 | DWORD size = static_cast(end - start); 107 | WriteConsoleA(out_handle_, msg.formatted.data() + start, size, nullptr, nullptr); 108 | } 109 | }; 110 | 111 | // 112 | // windows color console to stdout 113 | // 114 | template 115 | class wincolor_stdout_sink : public wincolor_sink 116 | { 117 | public: 118 | wincolor_stdout_sink() 119 | : wincolor_sink(GetStdHandle(STD_OUTPUT_HANDLE)) 120 | { 121 | } 122 | }; 123 | 124 | using wincolor_stdout_sink_mt = wincolor_stdout_sink; 125 | using wincolor_stdout_sink_st = wincolor_stdout_sink; 126 | 127 | // 128 | // windows color console to stderr 129 | // 130 | template 131 | class wincolor_stderr_sink : public wincolor_sink 132 | { 133 | public: 134 | wincolor_stderr_sink() 135 | : wincolor_sink(GetStdHandle(STD_ERROR_HANDLE)) 136 | { 137 | } 138 | }; 139 | 140 | using wincolor_stderr_sink_mt = wincolor_stderr_sink; 141 | using wincolor_stderr_sink_st = wincolor_stderr_sink; 142 | 143 | } // namespace sinks 144 | } // namespace spdlog 145 | -------------------------------------------------------------------------------- /include/spdlog/sinks/windebug_sink.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright(c) 2017 Alexander Dalshov. 3 | // Distributed under the MIT License (http://opensource.org/licenses/MIT) 4 | // 5 | 6 | #pragma once 7 | 8 | #if defined(_WIN32) 9 | 10 | #include "msvc_sink.h" 11 | 12 | namespace spdlog { 13 | namespace sinks { 14 | 15 | /* 16 | * Windows debug sink (logging using OutputDebugStringA, synonym for msvc_sink) 17 | */ 18 | template 19 | using windebug_sink = msvc_sink; 20 | 21 | using windebug_sink_mt = msvc_sink_mt; 22 | using windebug_sink_st = msvc_sink_st; 23 | 24 | } // namespace sinks 25 | } // namespace spdlog 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /include/spdlog/tweakme.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 | /////////////////////////////////////////////////////////////////////////////// 9 | // 10 | // Edit this file to squeeze more performance, and to customize supported features 11 | // 12 | /////////////////////////////////////////////////////////////////////////////// 13 | 14 | /////////////////////////////////////////////////////////////////////////////// 15 | // Under Linux, the much faster CLOCK_REALTIME_COARSE clock can be used. 16 | // This clock is less accurate - can be off by dozens of millis - depending on the kernel HZ. 17 | // Uncomment to use it instead of the regular clock. 18 | // 19 | // #define SPDLOG_CLOCK_COARSE 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | /////////////////////////////////////////////////////////////////////////////// 23 | // Uncomment if date/time logging is not needed and never appear in the log pattern. 24 | // This will prevent spdlog from querying the clock on each log call. 25 | // 26 | // WARNING: If the log pattern contains any date/time while this flag is on, the result is undefined. 27 | // You must set new pattern(spdlog::set_pattern(..") without any date/time in it 28 | // 29 | // #define SPDLOG_NO_DATETIME 30 | /////////////////////////////////////////////////////////////////////////////// 31 | 32 | /////////////////////////////////////////////////////////////////////////////// 33 | // Uncomment if thread id logging is not needed (i.e. no %t in the log pattern). 34 | // This will prevent spdlog from querying the thread id on each log call. 35 | // 36 | // WARNING: If the log pattern contains thread id (i.e, %t) while this flag is on, the result is undefined. 37 | // 38 | // #define SPDLOG_NO_THREAD_ID 39 | /////////////////////////////////////////////////////////////////////////////// 40 | 41 | /////////////////////////////////////////////////////////////////////////////// 42 | // Uncomment to prevent spdlog from caching thread ids in thread local storage. 43 | // By default spdlog saves thread ids in tls to gain a few micros for each call. 44 | // 45 | // WARNING: if your program forks, UNCOMMENT this flag to prevent undefined thread ids in the children logs. 46 | // 47 | // #define SPDLOG_DISABLE_TID_CACHING 48 | /////////////////////////////////////////////////////////////////////////////// 49 | 50 | /////////////////////////////////////////////////////////////////////////////// 51 | // Uncomment if logger name logging is not needed. 52 | // This will prevent spdlog from copying the logger name on each log call. 53 | // 54 | // #define SPDLOG_NO_NAME 55 | /////////////////////////////////////////////////////////////////////////////// 56 | 57 | /////////////////////////////////////////////////////////////////////////////// 58 | // Uncomment to enable the SPDLOG_DEBUG/SPDLOG_TRACE macros. 59 | // 60 | // #define SPDLOG_DEBUG_ON 61 | // #define SPDLOG_TRACE_ON 62 | /////////////////////////////////////////////////////////////////////////////// 63 | 64 | /////////////////////////////////////////////////////////////////////////////// 65 | // Uncomment to avoid locking in the registry operations (spdlog::get(), spdlog::drop() spdlog::register()). 66 | // Use only if your code never modifies concurrently the registry. 67 | // Note that upon creating a logger the registry is modified by spdlog.. 68 | // 69 | // #define SPDLOG_NO_REGISTRY_MUTEX 70 | /////////////////////////////////////////////////////////////////////////////// 71 | 72 | /////////////////////////////////////////////////////////////////////////////// 73 | // Uncomment to avoid spdlog's usage of atomic log levels 74 | // Use only if your code never modifies a logger's log levels concurrently by different threads. 75 | // 76 | // #define SPDLOG_NO_ATOMIC_LEVELS 77 | /////////////////////////////////////////////////////////////////////////////// 78 | 79 | /////////////////////////////////////////////////////////////////////////////// 80 | // Uncomment to enable usage of wchar_t for file names on Windows. 81 | // 82 | // #define SPDLOG_WCHAR_FILENAMES 83 | /////////////////////////////////////////////////////////////////////////////// 84 | 85 | /////////////////////////////////////////////////////////////////////////////// 86 | // Uncomment to override default eol ("\n" or "\r\n" under Linux/Windows) 87 | // 88 | // #define SPDLOG_EOL ";-)\n" 89 | /////////////////////////////////////////////////////////////////////////////// 90 | 91 | /////////////////////////////////////////////////////////////////////////////// 92 | // Uncomment to use your own copy of the fmt library instead of spdlog's copy. 93 | // In this case spdlog will try to include so set your -I flag accordingly. 94 | // 95 | // #define SPDLOG_FMT_EXTERNAL 96 | /////////////////////////////////////////////////////////////////////////////// 97 | 98 | /////////////////////////////////////////////////////////////////////////////// 99 | // Uncomment to use printf-style messages in your logs instead of the usual 100 | // format-style used by default. 101 | // 102 | // #define SPDLOG_FMT_PRINTF 103 | /////////////////////////////////////////////////////////////////////////////// 104 | 105 | /////////////////////////////////////////////////////////////////////////////// 106 | // Uncomment to enable syslog (disabled by default) 107 | // 108 | // #define SPDLOG_ENABLE_SYSLOG 109 | /////////////////////////////////////////////////////////////////////////////// 110 | 111 | /////////////////////////////////////////////////////////////////////////////// 112 | // Uncomment to enable wchar_t support (convert to utf8) 113 | // 114 | // #define SPDLOG_WCHAR_TO_UTF8_SUPPORT 115 | /////////////////////////////////////////////////////////////////////////////// 116 | 117 | /////////////////////////////////////////////////////////////////////////////// 118 | // Uncomment to prevent child processes from inheriting log file descriptors 119 | // 120 | // #define SPDLOG_PREVENT_CHILD_FD 121 | /////////////////////////////////////////////////////////////////////////////// 122 | 123 | /////////////////////////////////////////////////////////////////////////////// 124 | // Uncomment if your compiler doesn't support the "final" keyword. 125 | // The final keyword allows more optimizations in release 126 | // mode with recent compilers. See GCC's documentation for -Wsuggest-final-types 127 | // for instance. 128 | // 129 | // #define SPDLOG_NO_FINAL 130 | /////////////////////////////////////////////////////////////////////////////// 131 | 132 | /////////////////////////////////////////////////////////////////////////////// 133 | // Uncomment to enable message counting feature. 134 | // Use the %i in the logger pattern to display log message sequence id. 135 | // 136 | // #define SPDLOG_ENABLE_MESSAGE_COUNTER 137 | /////////////////////////////////////////////////////////////////////////////// 138 | 139 | /////////////////////////////////////////////////////////////////////////////// 140 | // Uncomment to customize level names (e.g. "MT TRACE") 141 | // 142 | // #define SPDLOG_LEVEL_NAMES { "MY TRACE", "MY DEBUG", "MY INFO", "MY WARNING", "MY ERROR", "MY CRITICAL", "OFF" } 143 | /////////////////////////////////////////////////////////////////////////////// 144 | -------------------------------------------------------------------------------- /include/vulkan/vk_platform.h: -------------------------------------------------------------------------------- 1 | // 2 | // File: vk_platform.h 3 | // 4 | /* 5 | ** Copyright (c) 2014-2017 The Khronos Group Inc. 6 | ** 7 | ** Licensed under the Apache License, Version 2.0 (the "License"); 8 | ** you may not use this file except in compliance with the License. 9 | ** You may obtain a copy of the License at 10 | ** 11 | ** http://www.apache.org/licenses/LICENSE-2.0 12 | ** 13 | ** Unless required by applicable law or agreed to in writing, software 14 | ** distributed under the License is distributed on an "AS IS" BASIS, 15 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ** See the License for the specific language governing permissions and 17 | ** limitations under the License. 18 | */ 19 | 20 | 21 | #ifndef VK_PLATFORM_H_ 22 | #define VK_PLATFORM_H_ 23 | 24 | #ifdef __cplusplus 25 | extern "C" 26 | { 27 | #endif // __cplusplus 28 | 29 | /* 30 | *************************************************************************************************** 31 | * Platform-specific directives and type declarations 32 | *************************************************************************************************** 33 | */ 34 | 35 | /* Platform-specific calling convention macros. 36 | * 37 | * Platforms should define these so that Vulkan clients call Vulkan commands 38 | * with the same calling conventions that the Vulkan implementation expects. 39 | * 40 | * VKAPI_ATTR - Placed before the return type in function declarations. 41 | * Useful for C++11 and GCC/Clang-style function attribute syntax. 42 | * VKAPI_CALL - Placed after the return type in function declarations. 43 | * Useful for MSVC-style calling convention syntax. 44 | * VKAPI_PTR - Placed between the '(' and '*' in function pointer types. 45 | * 46 | * Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void); 47 | * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); 48 | */ 49 | #if defined(_WIN32) 50 | // On Windows, Vulkan commands use the stdcall convention 51 | #define VKAPI_ATTR 52 | #define VKAPI_CALL __stdcall 53 | #define VKAPI_PTR VKAPI_CALL 54 | #elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 55 | #error "Vulkan isn't supported for the 'armeabi' NDK ABI" 56 | #elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) 57 | // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" 58 | // calling convention, i.e. float parameters are passed in registers. This 59 | // is true even if the rest of the application passes floats on the stack, 60 | // as it does by default when compiling for the armeabi-v7a NDK ABI. 61 | #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) 62 | #define VKAPI_CALL 63 | #define VKAPI_PTR VKAPI_ATTR 64 | #else 65 | // On other platforms, use the default calling convention 66 | #define VKAPI_ATTR 67 | #define VKAPI_CALL 68 | #define VKAPI_PTR 69 | #endif 70 | 71 | #include 72 | 73 | #if !defined(VK_NO_STDINT_H) 74 | #if defined(_MSC_VER) && (_MSC_VER < 1600) 75 | typedef signed __int8 int8_t; 76 | typedef unsigned __int8 uint8_t; 77 | typedef signed __int16 int16_t; 78 | typedef unsigned __int16 uint16_t; 79 | typedef signed __int32 int32_t; 80 | typedef unsigned __int32 uint32_t; 81 | typedef signed __int64 int64_t; 82 | typedef unsigned __int64 uint64_t; 83 | #else 84 | #include 85 | #endif 86 | #endif // !defined(VK_NO_STDINT_H) 87 | 88 | #ifdef __cplusplus 89 | } // extern "C" 90 | #endif // __cplusplus 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /include/vulkan/vulkan.h: -------------------------------------------------------------------------------- 1 | #ifndef VULKAN_H_ 2 | #define VULKAN_H_ 1 3 | 4 | /* 5 | ** Copyright (c) 2015-2018 The Khronos Group Inc. 6 | ** 7 | ** Licensed under the Apache License, Version 2.0 (the "License"); 8 | ** you may not use this file except in compliance with the License. 9 | ** You may obtain a copy of the License at 10 | ** 11 | ** http://www.apache.org/licenses/LICENSE-2.0 12 | ** 13 | ** Unless required by applicable law or agreed to in writing, software 14 | ** distributed under the License is distributed on an "AS IS" BASIS, 15 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ** See the License for the specific language governing permissions and 17 | ** limitations under the License. 18 | */ 19 | 20 | #include "vk_platform.h" 21 | #include "vulkan_core.h" 22 | 23 | #ifdef VK_USE_PLATFORM_ANDROID_KHR 24 | #include "vulkan_android.h" 25 | #endif 26 | 27 | 28 | #ifdef VK_USE_PLATFORM_IOS_MVK 29 | #include "vulkan_ios.h" 30 | #endif 31 | 32 | 33 | #ifdef VK_USE_PLATFORM_MACOS_MVK 34 | #include "vulkan_macos.h" 35 | #endif 36 | 37 | 38 | #ifdef VK_USE_PLATFORM_MIR_KHR 39 | #include 40 | #include "vulkan_mir.h" 41 | #endif 42 | 43 | 44 | #ifdef VK_USE_PLATFORM_VI_NN 45 | #include "vulkan_vi.h" 46 | #endif 47 | 48 | 49 | #ifdef VK_USE_PLATFORM_WAYLAND_KHR 50 | #include 51 | #include "vulkan_wayland.h" 52 | #endif 53 | 54 | 55 | #ifdef VK_USE_PLATFORM_WIN32_KHR 56 | #include 57 | #include "vulkan_win32.h" 58 | #endif 59 | 60 | 61 | #ifdef VK_USE_PLATFORM_XCB_KHR 62 | #include 63 | #include "vulkan_xcb.h" 64 | #endif 65 | 66 | 67 | #ifdef VK_USE_PLATFORM_XLIB_KHR 68 | #include 69 | #include "vulkan_xlib.h" 70 | #endif 71 | 72 | 73 | #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 74 | #include 75 | #include 76 | #include "vulkan_xlib_xrandr.h" 77 | #endif 78 | 79 | #endif // VULKAN_H_ 80 | -------------------------------------------------------------------------------- /include/vulkan/vulkan_android.h: -------------------------------------------------------------------------------- 1 | #ifndef VULKAN_ANDROID_H_ 2 | #define VULKAN_ANDROID_H_ 1 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /* 9 | ** Copyright (c) 2015-2018 The Khronos Group Inc. 10 | ** 11 | ** Licensed under the Apache License, Version 2.0 (the "License"); 12 | ** you may not use this file except in compliance with the License. 13 | ** You may obtain a copy of the License at 14 | ** 15 | ** http://www.apache.org/licenses/LICENSE-2.0 16 | ** 17 | ** Unless required by applicable law or agreed to in writing, software 18 | ** distributed under the License is distributed on an "AS IS" BASIS, 19 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | ** See the License for the specific language governing permissions and 21 | ** limitations under the License. 22 | */ 23 | 24 | /* 25 | ** This header is generated from the Khronos Vulkan XML API Registry. 26 | ** 27 | */ 28 | 29 | 30 | #define VK_KHR_android_surface 1 31 | struct ANativeWindow; 32 | 33 | #define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6 34 | #define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "VK_KHR_android_surface" 35 | 36 | typedef VkFlags VkAndroidSurfaceCreateFlagsKHR; 37 | 38 | typedef struct VkAndroidSurfaceCreateInfoKHR { 39 | VkStructureType sType; 40 | const void* pNext; 41 | VkAndroidSurfaceCreateFlagsKHR flags; 42 | struct ANativeWindow* window; 43 | } VkAndroidSurfaceCreateInfoKHR; 44 | 45 | 46 | typedef VkResult (VKAPI_PTR *PFN_vkCreateAndroidSurfaceKHR)(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); 47 | 48 | #ifndef VK_NO_PROTOTYPES 49 | VKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR( 50 | VkInstance instance, 51 | const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, 52 | const VkAllocationCallbacks* pAllocator, 53 | VkSurfaceKHR* pSurface); 54 | #endif 55 | 56 | #define VK_ANDROID_external_memory_android_hardware_buffer 1 57 | struct AHardwareBuffer; 58 | 59 | #define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION 3 60 | #define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME "VK_ANDROID_external_memory_android_hardware_buffer" 61 | 62 | typedef struct VkAndroidHardwareBufferUsageANDROID { 63 | VkStructureType sType; 64 | void* pNext; 65 | uint64_t androidHardwareBufferUsage; 66 | } VkAndroidHardwareBufferUsageANDROID; 67 | 68 | typedef struct VkAndroidHardwareBufferPropertiesANDROID { 69 | VkStructureType sType; 70 | void* pNext; 71 | VkDeviceSize allocationSize; 72 | uint32_t memoryTypeBits; 73 | } VkAndroidHardwareBufferPropertiesANDROID; 74 | 75 | typedef struct VkAndroidHardwareBufferFormatPropertiesANDROID { 76 | VkStructureType sType; 77 | void* pNext; 78 | VkFormat format; 79 | uint64_t externalFormat; 80 | VkFormatFeatureFlags formatFeatures; 81 | VkComponentMapping samplerYcbcrConversionComponents; 82 | VkSamplerYcbcrModelConversion suggestedYcbcrModel; 83 | VkSamplerYcbcrRange suggestedYcbcrRange; 84 | VkChromaLocation suggestedXChromaOffset; 85 | VkChromaLocation suggestedYChromaOffset; 86 | } VkAndroidHardwareBufferFormatPropertiesANDROID; 87 | 88 | typedef struct VkImportAndroidHardwareBufferInfoANDROID { 89 | VkStructureType sType; 90 | const void* pNext; 91 | struct AHardwareBuffer* buffer; 92 | } VkImportAndroidHardwareBufferInfoANDROID; 93 | 94 | typedef struct VkMemoryGetAndroidHardwareBufferInfoANDROID { 95 | VkStructureType sType; 96 | const void* pNext; 97 | VkDeviceMemory memory; 98 | } VkMemoryGetAndroidHardwareBufferInfoANDROID; 99 | 100 | typedef struct VkExternalFormatANDROID { 101 | VkStructureType sType; 102 | void* pNext; 103 | uint64_t externalFormat; 104 | } VkExternalFormatANDROID; 105 | 106 | 107 | typedef VkResult (VKAPI_PTR *PFN_vkGetAndroidHardwareBufferPropertiesANDROID)(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties); 108 | typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryAndroidHardwareBufferANDROID)(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer); 109 | 110 | #ifndef VK_NO_PROTOTYPES 111 | VKAPI_ATTR VkResult VKAPI_CALL vkGetAndroidHardwareBufferPropertiesANDROID( 112 | VkDevice device, 113 | const struct AHardwareBuffer* buffer, 114 | VkAndroidHardwareBufferPropertiesANDROID* pProperties); 115 | 116 | VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryAndroidHardwareBufferANDROID( 117 | VkDevice device, 118 | const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, 119 | struct AHardwareBuffer** pBuffer); 120 | #endif 121 | 122 | #ifdef __cplusplus 123 | } 124 | #endif 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /include/vulkan/vulkan_macos.h: -------------------------------------------------------------------------------- 1 | #ifndef VULKAN_MACOS_H_ 2 | #define VULKAN_MACOS_H_ 1 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /* 9 | ** Copyright (c) 2015-2018 The Khronos Group Inc. 10 | ** 11 | ** Licensed under the Apache License, Version 2.0 (the "License"); 12 | ** you may not use this file except in compliance with the License. 13 | ** You may obtain a copy of the License at 14 | ** 15 | ** http://www.apache.org/licenses/LICENSE-2.0 16 | ** 17 | ** Unless required by applicable law or agreed to in writing, software 18 | ** distributed under the License is distributed on an "AS IS" BASIS, 19 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | ** See the License for the specific language governing permissions and 21 | ** limitations under the License. 22 | */ 23 | 24 | /* 25 | ** This header is generated from the Khronos Vulkan XML API Registry. 26 | ** 27 | */ 28 | 29 | 30 | #define VK_MVK_macos_surface 1 31 | #define VK_MVK_MACOS_SURFACE_SPEC_VERSION 2 32 | #define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface" 33 | 34 | typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; 35 | 36 | typedef struct VkMacOSSurfaceCreateInfoMVK { 37 | VkStructureType sType; 38 | const void* pNext; 39 | VkMacOSSurfaceCreateFlagsMVK flags; 40 | const void* pView; 41 | } VkMacOSSurfaceCreateInfoMVK; 42 | 43 | 44 | typedef VkResult (VKAPI_PTR *PFN_vkCreateMacOSSurfaceMVK)(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); 45 | 46 | #ifndef VK_NO_PROTOTYPES 47 | VKAPI_ATTR VkResult VKAPI_CALL vkCreateMacOSSurfaceMVK( 48 | VkInstance instance, 49 | const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, 50 | const VkAllocationCallbacks* pAllocator, 51 | VkSurfaceKHR* pSurface); 52 | #endif 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif -------------------------------------------------------------------------------- /src/AmberMain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifdef __ANDROID__ 6 | #include 7 | #include 8 | #elif defined(AMBER_COCOA) 9 | // Defer to an Objective C file here. 10 | #else 11 | #include 12 | #endif 13 | 14 | #include 15 | 16 | #include 17 | 18 | using namespace par; 19 | 20 | static AmberApplication* g_vulkanApp = nullptr; 21 | static AmberApplication::SurfaceFn g_createSurface; 22 | static Vector2 g_cp; 23 | static Vector2 g_offset; 24 | static int g_buttonEvent; 25 | 26 | static double get_current_time() { 27 | using namespace std; 28 | static auto start = chrono::high_resolution_clock::now(); 29 | auto now = chrono::high_resolution_clock::now(); 30 | return 0.001 * chrono::duration_cast(now - start).count(); 31 | } 32 | 33 | #ifdef __ANDROID__ 34 | 35 | static void handle_cmd(android_app* app, int32_t cmd) { 36 | auto& prefs = AmberApplication::prefs(); 37 | auto createSurface = [app](VkInstance instance) { 38 | VkAndroidSurfaceCreateInfoKHR createInfo { 39 | .sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, 40 | .window = app->window 41 | }; 42 | VkSurfaceKHR surface; 43 | vkCreateAndroidSurfaceKHR(instance, &createInfo, nullptr, &surface); 44 | return surface; 45 | }; 46 | switch (cmd) { 47 | case APP_CMD_INIT_WINDOW: 48 | g_vulkanApp = AmberApplication::createApp(prefs.first, createSurface); 49 | break; 50 | case APP_CMD_TERM_WINDOW: 51 | delete g_vulkanApp; 52 | break; 53 | default: 54 | __android_log_print(ANDROID_LOG_INFO, "VulkanApp", "event not handled: %d", cmd); 55 | } 56 | } 57 | 58 | void android_main(struct android_app* app) { 59 | app->onAppCmd = handle_cmd; 60 | int events; 61 | android_poll_source* source; 62 | void** source_ptr = (void**) &source; 63 | do { 64 | auto result = ALooper_pollAll(g_vulkanApp ? 1 : 0, nullptr, &events, source_ptr); 65 | if (result >= 0 && source) { 66 | source->process(app, source); 67 | } 68 | if (g_vulkanApp) { 69 | g_vulkanApp->draw(get_current_time()); 70 | } 71 | } while (app->destroyRequested == 0); 72 | } 73 | 74 | #elif defined(AMBER_COCOA) 75 | // Defer to an Objective C file here. 76 | #else 77 | 78 | int main(const int argc, const char *argv[]) { 79 | auto& prefs = AmberApplication::prefs(); 80 | 81 | glfwInit(); 82 | glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); 83 | glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); 84 | glfwWindowHint(GLFW_DECORATED, prefs.decorated); 85 | // glfwWindowHint(GLFW_TRANSPARENT, GLFW_TRUE); 86 | 87 | auto window = glfwCreateWindow(prefs.width, prefs.height, prefs.title.c_str(), 0, 0); 88 | 89 | g_createSurface = [window] (VkInstance instance) { 90 | VkSurfaceKHR surface; 91 | glfwCreateWindowSurface(instance, window, nullptr, &surface); 92 | return surface; 93 | }; 94 | 95 | g_vulkanApp = AmberApplication::createApp(prefs.first, g_createSurface); 96 | 97 | glfwSetCursorPosCallback(window, [] (GLFWwindow* window, double x, double y) { 98 | if (g_buttonEvent == 1) { 99 | g_offset.x = x - g_cp.x; 100 | g_offset.y = y - g_cp.y; 101 | } 102 | }); 103 | 104 | glfwSetMouseButtonCallback(window, [] (GLFWwindow* window, int button, int action, int mods) { 105 | if(button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS){ 106 | g_buttonEvent = 1; 107 | double x, y; 108 | glfwGetCursorPos(window, &x, &y); 109 | g_cp.x = floor(x); 110 | g_cp.y = floor(y); 111 | } 112 | if(button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE){ 113 | g_buttonEvent = 0; 114 | g_cp.x = 0; 115 | g_cp.y = 0; 116 | } 117 | }); 118 | 119 | glfwSetKeyCallback(window, [] (GLFWwindow* window, int key, int, int action, int) { 120 | if (action != GLFW_RELEASE) { 121 | return; 122 | } 123 | switch (key) { 124 | case GLFW_KEY_ESCAPE: 125 | glfwSetWindowShouldClose(window, GLFW_TRUE); 126 | break; 127 | case GLFW_KEY_SPACE: 128 | delete g_vulkanApp; 129 | g_vulkanApp = AmberApplication::restartApp(g_createSurface); 130 | break; 131 | case GLFW_KEY_LEFT: 132 | delete g_vulkanApp; 133 | g_vulkanApp = AmberApplication::createPreviousApp(g_createSurface); 134 | break; 135 | case GLFW_KEY_RIGHT: 136 | delete g_vulkanApp; 137 | g_vulkanApp = AmberApplication::createNextApp(g_createSurface); 138 | break; 139 | } 140 | g_vulkanApp->handleKey(key); 141 | }); 142 | 143 | while (!glfwWindowShouldClose(window)) { 144 | 145 | if (g_buttonEvent == 1) { 146 | int w_posx, w_posy; 147 | glfwGetWindowPos(window, &w_posx, &w_posy); 148 | glfwSetWindowPos(window, w_posx + g_offset.x, w_posy + g_offset.y); 149 | g_offset.x = 0; 150 | g_offset.y = 0; 151 | g_cp.x += g_offset.x; 152 | g_cp.y += g_offset.y; 153 | } 154 | 155 | glfwPollEvents(); 156 | g_vulkanApp->draw(get_current_time()); 157 | } 158 | delete g_vulkanApp; 159 | } 160 | 161 | #endif 162 | -------------------------------------------------------------------------------- /src/AmberProgram.cpp: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // Copyright (c) 2018 Philip Rideout 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "LavaInternal.h" 14 | 15 | using namespace par; 16 | using namespace std; 17 | 18 | #if !defined(__ANDROID__) && !defined(AMBER_COCOA) 19 | #define FILEWATCHER 20 | #endif 21 | 22 | #ifdef FILEWATCHER 23 | #include 24 | using namespace FW; 25 | #endif 26 | 27 | struct AmberProgramImpl : AmberProgram { 28 | AmberProgramImpl(const string& vshader, const string& fshader) noexcept; 29 | ~AmberProgramImpl() noexcept; 30 | VkShaderModule compileVertexShader(VkDevice device) noexcept; 31 | VkShaderModule compileFragmentShader(VkDevice device) noexcept; 32 | AmberCompiler* mCompiler; 33 | string mVertShader; 34 | string mFragShader; 35 | VkShaderModule mVertModule = VK_NULL_HANDLE; 36 | VkShaderModule mFragModule = VK_NULL_HANDLE; 37 | VkDevice mDevice = VK_NULL_HANDLE; 38 | #ifdef SUPPORT_FILEWATCHER 39 | FileWatcher mFileWatcher; 40 | struct : FileWatchListener { 41 | FileListener callback; 42 | void handleFileAction(WatchID watchid, const String& dir, const String& filename, 43 | Action action) override { 44 | if (action == Actions::Modified) { 45 | if (callback) { 46 | callback(filename); 47 | } 48 | } 49 | } 50 | } mFileListener; 51 | #endif 52 | }; 53 | 54 | LAVA_DEFINE_UPCAST(AmberProgram) 55 | 56 | AmberProgram* AmberProgram::create(const string& vshader, const string& fshader) noexcept { 57 | return new AmberProgramImpl(vshader, fshader); 58 | } 59 | 60 | void AmberProgram::operator delete(void* ptr) noexcept { 61 | auto impl = (AmberProgramImpl*) ptr; 62 | ::delete impl; 63 | } 64 | 65 | AmberProgramImpl::~AmberProgramImpl() noexcept { 66 | if (mDevice && mVertModule) { 67 | vkDestroyShaderModule(mDevice, mVertModule, VKALLOC); 68 | } 69 | if (mDevice && mFragModule) { 70 | vkDestroyShaderModule(mDevice, mFragModule, VKALLOC); 71 | } 72 | delete mCompiler; 73 | } 74 | 75 | AmberProgramImpl::AmberProgramImpl(const string& vshader, const string& fshader) noexcept : 76 | mCompiler(AmberCompiler::create()), mVertShader(vshader), mFragShader(fshader) {} 77 | 78 | VkShaderModule AmberProgramImpl::compileVertexShader(VkDevice device) noexcept { 79 | if (mVertModule) { 80 | return mVertModule; 81 | } 82 | std::vector spirv; 83 | if (!mCompiler->compile(AmberCompiler::VERTEX, mVertShader, &spirv)) { 84 | llog.error("Unable to compile vertex shader."); 85 | return VK_NULL_HANDLE; 86 | } 87 | VkShaderModuleCreateInfo moduleCreateInfo { 88 | .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 89 | .codeSize = spirv.size() * 4, 90 | .pCode = spirv.data() 91 | }; 92 | VkResult err = vkCreateShaderModule(device, &moduleCreateInfo, VKALLOC, &mVertModule); 93 | LOG_CHECK(!err, "Unable to create vertex shader module."); 94 | return mVertModule; 95 | } 96 | 97 | VkShaderModule AmberProgramImpl::compileFragmentShader(VkDevice device) noexcept { 98 | if (mFragModule) { 99 | return mFragModule; 100 | } 101 | std::vector spirv; 102 | if (!mCompiler->compile(AmberCompiler::FRAGMENT, mFragShader, &spirv)) { 103 | llog.error("Unable to compile fragment shader."); 104 | return VK_NULL_HANDLE; 105 | } 106 | VkShaderModuleCreateInfo moduleCreateInfo { 107 | .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 108 | .codeSize = spirv.size() * 4, 109 | .pCode = spirv.data() 110 | }; 111 | VkResult err = vkCreateShaderModule(device, &moduleCreateInfo, VKALLOC, &mFragModule); 112 | LOG_CHECK(!err, "Unable to create fragment shader module."); 113 | return mFragModule; 114 | } 115 | 116 | bool AmberProgram::compile(VkDevice device) noexcept { 117 | AmberProgramImpl& impl = *upcast(this); 118 | impl.compileVertexShader(device); 119 | impl.compileFragmentShader(device); 120 | impl.mDevice = device; 121 | return impl.mVertModule && impl.mFragModule; 122 | } 123 | 124 | VkShaderModule AmberProgram::getVertexShader() const noexcept { 125 | return upcast(this)->mVertModule; 126 | } 127 | 128 | VkShaderModule AmberProgram::getFragmentShader() const noexcept { 129 | return upcast(this)->mFragModule; 130 | } 131 | 132 | string AmberProgram::getChunk(const string& filename, const string& chunkName) noexcept { 133 | const regex pattern(R"([\s]+)"); 134 | sregex_token_iterator it(chunkName.begin(), chunkName.end(), pattern, -1); 135 | vector chunkids(it, {}); 136 | vector tokens; 137 | 138 | string chunk = "#version 450\n"; 139 | for (auto chunkid : chunkids) { 140 | chunk += "#line "; 141 | ifstream ifs(filename); 142 | bool extracting = false; 143 | int lineno = 1; 144 | for (string line; getline(ifs, line); ++lineno) { 145 | sregex_token_iterator it(line.begin(), line.end(), pattern, -1); 146 | vector tokens(it, {}); 147 | if (tokens.size() >= 2 && tokens[1] == chunkid) { 148 | chunk += to_string(lineno + 1) + "\n"; 149 | extracting = true; 150 | continue; 151 | } else if (!extracting) { 152 | continue; 153 | } 154 | if (!line.compare(0, 2, "--")) { 155 | extracting = false; 156 | } else { 157 | chunk += line + "\n"; 158 | } 159 | } 160 | } 161 | return chunk; 162 | } 163 | 164 | void AmberProgram::watchDirectory(const string& directory, FileListener onChange) noexcept { 165 | #ifdef SUPPORT_FILEWATCHER 166 | AmberProgramImpl& impl = *upcast(this); 167 | impl.mFileListener.callback = onChange; 168 | impl.mFileWatcher.addWatch(directory, &impl.mFileListener); 169 | #endif 170 | } 171 | 172 | void AmberProgram::checkDirectory() noexcept { 173 | #ifdef SUPPORT_FILEWATCHER 174 | AmberProgramImpl& impl = *upcast(this); 175 | impl.mFileWatcher.update(); 176 | #endif 177 | } 178 | -------------------------------------------------------------------------------- /src/LavaCpuBuffer.cpp: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // Copyright (c) 2018 Philip Rideout 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "LavaInternal.h" 9 | 10 | using namespace par; 11 | 12 | struct LavaCpuBufferImpl : LavaCpuBuffer { 13 | LavaCpuBufferImpl(Config config) noexcept; 14 | ~LavaCpuBufferImpl() noexcept; 15 | VkDevice device; 16 | VkBuffer buffer; 17 | VmaAllocation memory; 18 | VmaAllocator vma; 19 | uint32_t size; 20 | }; 21 | 22 | LAVA_DEFINE_UPCAST(LavaCpuBuffer) 23 | 24 | LavaCpuBuffer* LavaCpuBuffer::create(Config config) noexcept { 25 | return new LavaCpuBufferImpl(config); 26 | } 27 | 28 | void LavaCpuBuffer::operator delete(void* ptr) { 29 | auto impl = (LavaCpuBufferImpl*) ptr; 30 | ::delete impl; 31 | } 32 | 33 | LavaCpuBufferImpl::~LavaCpuBufferImpl() noexcept { 34 | vmaDestroyBuffer(vma, buffer, memory); 35 | } 36 | 37 | LavaCpuBufferImpl::LavaCpuBufferImpl(Config config) noexcept : device(config.device) { 38 | assert(config.device && config.gpu && config.size > 0); 39 | vma = getVma(config.device, config.gpu); 40 | VkBufferCreateInfo bufferInfo { 41 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 42 | .size = config.capacity ? config.capacity : config.size, 43 | .usage = config.usage 44 | }; 45 | size = config.size; 46 | VmaAllocationCreateInfo allocInfo { .usage = VMA_MEMORY_USAGE_CPU_TO_GPU }; 47 | vmaCreateBuffer(vma, &bufferInfo, &allocInfo, &buffer, &memory, nullptr); 48 | if (config.source) { 49 | setData(config.source, config.size); 50 | } 51 | } 52 | 53 | void LavaCpuBuffer::setData(void const* sourceData, uint32_t bytesToCopy, uint32_t offset) 54 | noexcept { 55 | auto impl = upcast(this); 56 | LOG_CHECK(offset + bytesToCopy <= impl->size, "Out of bounds upload."); 57 | uint8_t* mappedData; 58 | vmaMapMemory(impl->vma, impl->memory, (void**) &mappedData); 59 | memcpy(mappedData + offset, sourceData, bytesToCopy); 60 | vmaUnmapMemory(impl->vma, impl->memory); 61 | } 62 | 63 | uint8_t* LavaCpuBuffer::map() const noexcept { 64 | auto impl = upcast(this); 65 | uint8_t* mappedData; 66 | vmaMapMemory(impl->vma, impl->memory, (void**) &mappedData); 67 | return mappedData; 68 | } 69 | 70 | void LavaCpuBuffer::unmap() const noexcept { 71 | auto impl = upcast(this); 72 | vmaUnmapMemory(impl->vma, impl->memory); 73 | } 74 | 75 | VkBuffer LavaCpuBuffer::getBuffer() const noexcept { 76 | return upcast(this)->buffer; 77 | } 78 | -------------------------------------------------------------------------------- /src/LavaGpuBuffer.cpp: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // Copyright (c) 2018 Philip Rideout 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "LavaInternal.h" 9 | 10 | using namespace par; 11 | 12 | struct LavaGpuBufferImpl : LavaGpuBuffer { 13 | LavaGpuBufferImpl(Config config) noexcept; 14 | ~LavaGpuBufferImpl() noexcept; 15 | VkDevice device; 16 | VkBuffer buffer; 17 | VmaAllocation memory; 18 | VmaAllocator vma; 19 | }; 20 | 21 | LAVA_DEFINE_UPCAST(LavaGpuBuffer) 22 | 23 | LavaGpuBuffer* LavaGpuBuffer::create(Config config) noexcept { 24 | return new LavaGpuBufferImpl(config); 25 | } 26 | 27 | void LavaGpuBuffer::operator delete(void* ptr) { 28 | auto impl = (LavaGpuBufferImpl*) ptr; 29 | ::delete impl; 30 | } 31 | 32 | LavaGpuBufferImpl::~LavaGpuBufferImpl() noexcept { 33 | vmaDestroyBuffer(vma, buffer, memory); 34 | } 35 | 36 | LavaGpuBufferImpl::LavaGpuBufferImpl(Config config) noexcept : device(config.device) { 37 | assert(config.device && config.gpu && config.size > 0); 38 | vma = getVma(config.device, config.gpu); 39 | VkBufferCreateInfo bufferInfo { 40 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 41 | .size = config.size, 42 | .usage = config.usage 43 | }; 44 | VmaAllocationCreateInfo allocInfo { .usage = VMA_MEMORY_USAGE_GPU_ONLY }; 45 | vmaCreateBuffer(vma, &bufferInfo, &allocInfo, &buffer, &memory, nullptr); 46 | } 47 | 48 | VkBuffer LavaGpuBuffer::getBuffer() const noexcept { 49 | return upcast(this)->buffer; 50 | } 51 | 52 | const VkBuffer* LavaGpuBuffer::getBufferPtr() const noexcept { 53 | return &(upcast(this)->buffer); 54 | } 55 | -------------------------------------------------------------------------------- /src/LavaInternal.cpp: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // Copyright (c) 2018 Philip Rideout 3 | 4 | #include 5 | #include 6 | 7 | #define VMA_IMPLEMENTATION 8 | #include "LavaInternal.h" 9 | 10 | #include 11 | #include 12 | 13 | namespace par { 14 | 15 | static std::unordered_map sVmaAllocators; 16 | 17 | VmaAllocator getVma(VkDevice device, VkPhysicalDevice gpu) { 18 | VmaAllocator& vma = sVmaAllocators[device]; 19 | if (vma == VK_NULL_HANDLE) { 20 | createVma(device, gpu); 21 | } 22 | return vma; 23 | } 24 | 25 | void createVma(VkDevice device, VkPhysicalDevice gpu) { 26 | VmaVulkanFunctions funcs { 27 | .vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties, 28 | .vkGetPhysicalDeviceMemoryProperties = vkGetPhysicalDeviceMemoryProperties, 29 | .vkAllocateMemory = vkAllocateMemory, 30 | .vkFreeMemory = vkFreeMemory, 31 | .vkMapMemory = vkMapMemory, 32 | .vkUnmapMemory = vkUnmapMemory, 33 | .vkBindBufferMemory = vkBindBufferMemory, 34 | .vkBindImageMemory = vkBindImageMemory, 35 | .vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements, 36 | .vkGetImageMemoryRequirements = vkGetImageMemoryRequirements, 37 | .vkCreateBuffer = vkCreateBuffer, 38 | .vkDestroyBuffer = vkDestroyBuffer, 39 | .vkCreateImage = vkCreateImage, 40 | .vkDestroyImage = vkDestroyImage, 41 | .vkGetBufferMemoryRequirements2KHR = vkGetBufferMemoryRequirements2KHR, 42 | .vkGetImageMemoryRequirements2KHR = vkGetImageMemoryRequirements2KHR, 43 | }; 44 | VmaAllocatorCreateInfo info = { 45 | .physicalDevice = gpu, 46 | .device = device, 47 | .pVulkanFunctions = &funcs, 48 | }; 49 | auto& vma = sVmaAllocators[device] = VmaAllocator(); 50 | vmaCreateAllocator(&info, &vma); 51 | } 52 | 53 | void destroyVma(VkDevice device) { 54 | vmaDestroyAllocator(sVmaAllocators[device]); 55 | sVmaAllocators[device] = VK_NULL_HANDLE; 56 | } 57 | 58 | uint64_t getCurrentTime() { 59 | auto now = std::chrono::system_clock::now(); 60 | auto duration = now.time_since_epoch(); 61 | return std::chrono::duration_cast(duration).count(); 62 | } 63 | 64 | size_t murmurHash(uint32_t const* words, uint32_t nwords, uint32_t seed) { 65 | if (nwords == 0) { 66 | return 0; 67 | } 68 | uint32_t h = seed; 69 | size_t i = nwords; 70 | do { 71 | uint32_t k = *words++; 72 | k *= 0xcc9e2d51; 73 | k = (k << 15) | (k >> 17); 74 | k *= 0x1b873593; 75 | h ^= k; 76 | h = (h << 13) | (h >> 19); 77 | h = (h * 5) + 0xe6546b64; 78 | } while (--i); 79 | h ^= nwords; 80 | h ^= h >> 16; 81 | h *= 0x85ebca6b; 82 | h ^= h >> 13; 83 | h *= 0xc2b2ae35; 84 | h ^= h >> 16; 85 | return h; 86 | } 87 | 88 | } -------------------------------------------------------------------------------- /src/LavaInternal.h: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // Copyright (c) 2018 Philip Rideout 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | #define VKALLOC nullptr 9 | 10 | #if defined(__GNUC__) 11 | # define LAVA_UNUSED __attribute__ ((unused)) 12 | #elif defined(_MSC_VER) 13 | # define LAVA_UNUSED __pragma(warning(suppress:4100)) 14 | #else 15 | # define LAVA_UNUSED 16 | #endif 17 | 18 | #include "vk_mem_alloc.h" 19 | 20 | #define LAVA_DEFINE_UPCAST(CLASS) \ 21 | inline LAVA_UNUSED CLASS##Impl& upcast(CLASS& that) noexcept { \ 22 | return static_cast(that); \ 23 | } \ 24 | inline LAVA_UNUSED const CLASS##Impl& upcast(const CLASS& that) noexcept { \ 25 | return static_cast(that); \ 26 | } \ 27 | inline LAVA_UNUSED CLASS##Impl* upcast(CLASS* that) noexcept { \ 28 | return static_cast(that); \ 29 | } \ 30 | inline LAVA_UNUSED CLASS##Impl const* upcast(CLASS const* that) noexcept { \ 31 | return static_cast(that); \ 32 | } 33 | 34 | namespace par { 35 | 36 | VmaAllocator getVma(VkDevice device, VkPhysicalDevice gpu); 37 | void createVma(VkDevice device, VkPhysicalDevice gpu); 38 | void destroyVma(VkDevice device); 39 | 40 | uint64_t getCurrentTime(); 41 | size_t murmurHash(uint32_t const* words, uint32_t nwords, uint32_t seed); 42 | 43 | template 44 | struct MurmurHashFn { 45 | uint32_t operator()(const T& key) const { 46 | static_assert(0 == (sizeof(key) & 3), "Hashing requires a size that is a multiple of 4."); 47 | return murmurHash((uint32_t const *) &key, sizeof(key) / 4, 0u); 48 | } 49 | }; 50 | 51 | // Wraps a std::vector and exposes the data pointer and size as public fields. 52 | // 53 | // This works nicely with Vulkan queries. For example: 54 | // LavaVector props; 55 | // vkEnumerateInstanceExtensionProperties(nullptr, &props.size, nullptr); 56 | // vkEnumerateInstanceExtensionProperties(nullptr, &props.size, props.alloc()); 57 | template struct LavaVector { 58 | uint32_t size = 0; 59 | T* data = nullptr; 60 | LavaVector() {} 61 | LavaVector(std::initializer_list init) : mVector(init) { update(); } 62 | T* alloc() { 63 | mVector.resize(size); 64 | update(); 65 | return data; 66 | } 67 | T& operator[](size_t t) { 68 | return mVector[t]; 69 | } 70 | LavaVector& operator=(const LavaVector& that) { 71 | mVector = that.mVector; 72 | update(); 73 | return *this; 74 | } 75 | template void assign(II first, II last) { 76 | mVector.assign(first, last); 77 | update(); 78 | } 79 | void push_back(const T& t) { 80 | mVector.push_back(t); 81 | update(); 82 | } 83 | void clear() { 84 | mVector.clear(); 85 | update(); 86 | } 87 | typename std::vector::const_iterator begin() const { return mVector.begin(); } 88 | typename std::vector::const_iterator end() const { return mVector.end(); } 89 | private: 90 | void update() { 91 | data = mVector.data(); 92 | size = static_cast(mVector.size()); 93 | } 94 | std::vector mVector; 95 | }; 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/LavaLog.cpp: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // Copyright (c) 2018 Philip Rideout 3 | 4 | #include 5 | 6 | using namespace par; 7 | 8 | static bool sFirst = true; 9 | 10 | LavaLog par::llog; 11 | 12 | LavaLog::LavaLog() { 13 | if (sFirst) { 14 | #if defined(__ANDROID__) 15 | mLogger = spdlog::android_logger("console", "lava"); 16 | mLogger->set_pattern("%^%v%$"); 17 | #else 18 | mLogger = spdlog::stdout_color_mt("console"); 19 | mLogger->set_pattern("%T %t %^%v%$"); 20 | #endif 21 | #ifndef NDEBUG 22 | //mLogger->set_level(spdlog::level::debug); 23 | #endif 24 | sFirst = false; 25 | } else { 26 | mLogger = spdlog::get("console"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/LavaTexture.cpp: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | // Copyright (c) 2018 Philip Rideout 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "LavaInternal.h" 9 | 10 | using namespace par; 11 | 12 | struct LavaTextureImpl : LavaTexture { 13 | LavaTextureImpl(Config config) noexcept; 14 | ~LavaTextureImpl() noexcept; 15 | VkDevice device; 16 | VmaAllocation stageMem; 17 | VmaAllocation imageMem; 18 | VmaAllocator vma; 19 | VkFormat format; 20 | VkExtent3D size; 21 | VkBuffer stage; 22 | VkImage image; 23 | VkImageView view; 24 | void uploadStage(VkCommandBuffer cmd) const noexcept; 25 | }; 26 | 27 | LAVA_DEFINE_UPCAST(LavaTexture) 28 | 29 | LavaTexture* LavaTexture::create(Config config) noexcept { 30 | return new LavaTextureImpl(config); 31 | } 32 | 33 | void LavaTexture::operator delete(void* ptr) noexcept { 34 | auto impl = (LavaTextureImpl*) ptr; 35 | ::delete impl; 36 | } 37 | 38 | LavaTextureImpl::~LavaTextureImpl() noexcept { 39 | vmaDestroyBuffer(vma, stage, stageMem); 40 | vmaDestroyImage(vma, image, imageMem); 41 | vkDestroyImageView(device, view, VKALLOC); 42 | } 43 | 44 | LavaTextureImpl::LavaTextureImpl(Config config) noexcept : device(config.device) { 45 | assert(config.device && config.gpu && config.size > 0); 46 | format = config.format; 47 | size = { config.width, config.height, 1 }; 48 | vma = getVma(config.device, config.gpu); 49 | VkBufferCreateInfo bufferInfo { 50 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 51 | .size = config.size, 52 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT 53 | }; 54 | VkImageCreateInfo imageInfo { 55 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 56 | .imageType = VK_IMAGE_TYPE_2D, 57 | .extent = size, 58 | .format = format, 59 | .mipLevels = 1, 60 | .arrayLayers = 1, 61 | .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 62 | .samples = VK_SAMPLE_COUNT_1_BIT, 63 | }; 64 | VmaAllocationCreateInfo stageInfo { .usage = VMA_MEMORY_USAGE_CPU_TO_GPU }; 65 | vmaCreateBuffer(vma, &bufferInfo, &stageInfo, &stage, &stageMem, nullptr); 66 | if (config.source) { 67 | void* mappedData; 68 | vmaMapMemory(vma, stageMem, &mappedData); 69 | memcpy(mappedData, config.source, config.size); 70 | vmaUnmapMemory(vma, stageMem); 71 | } 72 | VmaAllocationCreateInfo allocInfo { .usage = VMA_MEMORY_USAGE_GPU_ONLY }; 73 | vmaCreateImage(vma, &imageInfo, &allocInfo, &image, &imageMem, nullptr); 74 | 75 | VkImageViewCreateInfo colorViewInfo { 76 | .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 77 | .image = image, 78 | .viewType = VK_IMAGE_VIEW_TYPE_2D, 79 | .format = format, 80 | .subresourceRange = { 81 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 82 | .levelCount = 1, 83 | .layerCount = 1 84 | } 85 | }; 86 | vkCreateImageView(config.device, &colorViewInfo, VKALLOC, &view); 87 | } 88 | 89 | void LavaTextureImpl::uploadStage(VkCommandBuffer cmd) const noexcept { 90 | const int miplevel = 0; 91 | VkImageMemoryBarrier barrier1 { 92 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 93 | .image = image, 94 | .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, 95 | .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 96 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 97 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 98 | .subresourceRange = { 99 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 100 | .baseMipLevel = miplevel, 101 | .levelCount = 1, 102 | .layerCount = 1, 103 | }, 104 | .srcAccessMask = 0, 105 | .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT 106 | }; 107 | VkBufferImageCopy upload { 108 | .imageSubresource = { 109 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 110 | .mipLevel = miplevel, 111 | .layerCount = 1, 112 | }, 113 | .imageExtent = { 114 | .width = size.width >> miplevel, 115 | .height = size.height >> miplevel, 116 | .depth = 1, 117 | } 118 | }; 119 | VkImageMemoryBarrier barrier2 { 120 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 121 | .image = image, 122 | .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 123 | .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 124 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 125 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, 126 | .subresourceRange = { 127 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, 128 | .baseMipLevel = miplevel, 129 | .levelCount = 1, 130 | .layerCount = 1, 131 | }, 132 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, 133 | .dstAccessMask = VK_ACCESS_SHADER_READ_BIT 134 | }; 135 | vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 136 | VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier1); 137 | vkCmdCopyBufferToImage(cmd, stage, image, 138 | VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &upload); 139 | vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, 140 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier2); 141 | } 142 | 143 | VkImageView LavaTexture::getImageView() const noexcept { 144 | return upcast(this)->view; 145 | } 146 | 147 | void LavaTexture::freeStage() noexcept { 148 | LavaTextureImpl& impl = *upcast(this); 149 | vmaDestroyBuffer(impl.vma, impl.stage, impl.stageMem); 150 | impl.stage = 0; 151 | impl.stageMem = 0; 152 | } 153 | 154 | void LavaTexture::uploadStage(VkCommandBuffer cmd) const noexcept { 155 | upcast(this)->uploadStage(cmd); 156 | } 157 | --------------------------------------------------------------------------------