Slide 1

Slide 1 text

௿ϨΠϠʔ͔Β࢝ΊΔ GUI NAOMASA MATSUBAYASHI (@fadis_)

Slide 2

Slide 2 text

GPU

Slide 3

Slide 3 text

ϏσΦϝϞϦ GPUͷ2ͭͷػೳ ϏσΦϝϞϦͷ಺༰Λը໘ʹ දࣔ͢Δ ϏσΦϝϞϦ্ͷ஋ΛಡΈॻ͖ͯ͠ ܭࢉ͢Δ

Slide 4

Slide 4 text

GPU࢖͍͍ͨ GPU࢖͍͍ͨ ϓϩηε1 ϓϩηε2 εέδϡʔϥ ࠓ͸ϓϩηε1ʹGPUΛ࢖ΘͤΑ͏ ଴ػ ϏσΦϝϞϦ ϓϩηε1ͷ σʔλ ϓϩηε2ͷ σʔλ ܭࢉͷػೳΛڞ༗͢Δ

Slide 5

Slide 5 text

GPU࢖͍͍ͨ GPU࢖͍͍ͨ ϓϩηε1 ϓϩηε2 εέδϡʔϥ ࠓ͸ϓϩηε2ʹGPUΛ࢖ΘͤΑ͏ ଴ػ ϏσΦϝϞϦ ϓϩηε1ͷ σʔλ ϓϩηε2ͷ σʔλ ܭࢉͷػೳΛڞ༗͢Δ

Slide 6

Slide 6 text

ը໘ʹ Λද͍ࣔͨ͠ ը໘ʹ Λද͍ࣔͨ͠ ϓϩηε1 ϓϩηε2 ϏσΦϝϞϦ ? දࣔͷػೳΛڞ༗͢Δํ๏͸ࣗ໌Ͱ͸ͳ͍ ?

Slide 7

Slide 7 text

Χʔωϧۭؒ DRM/KMS Ϣʔβۭؒ Ϣʔβۭؒ Ϣʔβۭؒ εέδϡʔϥ Ϩϯμʔϊʔυ ܭࢉ දࣔ LinuxͰͷ GPUͷѻ͍ Linux ϓϥΠϚϦϊʔυ

Slide 8

Slide 8 text

Χʔωϧۭؒ DRM/KMS Ϣʔβۭؒ Ϣʔβۭؒ Ϣʔβۭؒ εέδϡʔϥ Ϩϯμʔϊʔυ ܭࢉ දࣔ LinuxͰͷ GPUͷѻ͍ Linux ϓϥΠϚϦϊʔυ Ϩϯμʔϊʔυ /dev/dri/renderD128ͱ͔ GPUͷϝϞϦΛ֬อͰ͖Δ GPUͰܭࢉͰ͖Δ දࣔ͸Ͱ͖ͳ͍ ͜ͷσόΠεΛհͯ͠ ෳ਺ͷϓϩηε͕ಉ࣌ʹ ͜ͷσόΠεΛ։͚Δ

Slide 9

Slide 9 text

ϧۭؒ DRM/KMS Ϣʔβۭؒ Ϣʔβۭؒ Ϣʔβۭؒ εέδϡʔϥ Ϩϯμʔϊʔυ ܭࢉ දࣔ uxͰͷ Uͷѻ͍ ux ϓϥΠϚϦϊʔυ ϓϥΠϚϦϊʔυ /dev/dri/card0ͱ͔ GPUͷϝϞϦΛ֬อͰ͖Δ GPUͰܭࢉͰ͖Δ දࣔ΋Ͱ͖Δ ͜ͷσόΠεΛհͯ͠ ಉ࣌ʹ͜ͷσόΠεΛ ։͚Δϓϩηε͸1͚ͭͩ

Slide 10

Slide 10 text

ϏσΦϝϞϦ Χʔωϧۭؒ Ϣʔβۭؒ Ϣʔβۭؒ Ϣʔβۭؒ ද ࣔ Linux αʔό ΫϥΠΞϯτ ΫϥΠΞϯτ ॻ ͘ ಡ Ή Ϩϯμʔϊʔυ ಡ Ή ॻ ͘ ॻ ͘ ϓϥΠϚϦϊʔυ ͓લɺڞ༗ϝϞϦʹॻ͘ Զɺڞ༗ϝϞϦΛಡΉ ॻ͍ͨ Window System

Slide 11

Slide 11 text

ϏσΦϝϞϦ Χʔωϧۭؒ Ϣʔβۭؒ Ϣʔβۭؒ Ϣʔβۭؒ ද ࣔ Linux Wayland ίϯϙδλ Wayland ΫϥΠΞϯτ ॻ ͘ ಡ Ή Ϩϯμʔϊʔυ ಡ Ή ॻ ͘ ॻ ͘ ϓϥΠϚϦϊʔυ ͓લɺڞ༗ϝϞϦʹॻ͘ Զɺڞ༗ϝϞϦΛಡΉ ॻ͍ͨ Wayland Wayland ΫϥΠΞϯτ

Slide 12

Slide 12 text

ϏσΦϝϞϦ Χʔωϧۭؒ Ϣʔβۭؒ Linux Mesa ϋʔυ΢ΣΞඇґଘͷ GPUͷૢ࡞ ಛఆͷGPU޲͚ͷ ίϚϯυ Ϩϯμʔϊʔυ libdrm QtɺGTK+౳ ΞϓϦέʔγϣϯ ΢Οδοτͷૢ࡞ ڞ༗ϝϞϦ ϓϥΠϚϦϊʔυ

Slide 13

Slide 13 text

ϏσΦϝϞϦ Χʔωϧۭؒ Ϣʔβۭؒ Linux Mesa Ϩϯμʔϊʔυ libdrm QtɺGTK+౳ ΞϓϦέʔγϣϯ Ϣʔβۭؒ αʔό xcb ڞ༗ϝϞϦ͍ͩ͘͞ ڞ༗ϝϞϦ ͜ΕΛ࢖ͬͯ ͜͜ʹඳ͍ͯ ڞ༗ϝϞϦ ͍ͩ͘͞ Mesa libdrm ϓϥΠϚϦϊʔυ ͜ΕΛ ࢖ͬͯ

Slide 14

Slide 14 text

ϏσΦϝϞϦ Χʔωϧۭؒ Ϣʔβۭؒ Linux Mesa Ϩϯμʔϊʔυ libdrm QtɺGTK+౳ ΞϓϦέʔγϣϯ Ϣʔβۭؒ αʔό xcb ඳ͖ऴΘͬͨ Mesa libdrm ϓϥΠϚϦϊʔυ ͔͜͜Β ͜͜΁ ίϐʔ ඳ͖ऴΘͬͨ ϋʔυ΢ΣΞඇґଘͷ GPUͷૢ࡞ ಛఆͷGPU޲͚ͷ ίϚϯυ

Slide 15

Slide 15 text

ϏσΦϝϞϦ Χʔωϧۭؒ Ϣʔβۭؒ Linux Mesa Ϩϯμʔϊʔυ libdrm QtɺGTK+౳ ΞϓϦέʔγϣϯ Ϣʔβۭؒ αʔό xcb Mesa libdrm ϓϥΠϚϦϊʔυ ͜ΕΛදࣔͯ͠ ϋʔυ΢ΣΞඇґଘͷ GPUͷૢ࡞ ಛఆͷGPU޲͚ͷ ίϚϯυ

Slide 16

Slide 16 text

ϏσΦϝϞϦ Χʔωϧۭؒ Ϣʔβۭؒ Linux Mesa Ϩϯμʔϊʔυ libdrm ΞϓϦέʔγϣϯ Ϣʔβۭؒ αʔό xcb ڞ༗ϝϞϦ Mesa libdrm ϓϥΠϚϦϊʔυ ϋʔυ΢ΣΞඇґଘͷ GPUͷૢ࡞ ಛఆͷGPU޲͚ͷ ίϚϯυ ΞϓϦέʔγϣϯ͕ Vulkan΍OpenGLΛ ௚઀஻Δ৔߹

Slide 17

Slide 17 text

Ϣʔβۭؒ Mesa ΞϓϦέʔγϣϯ ϋʔυ΢ΣΞඇґଘͷ GPUͷૢ࡞ ಛఆͷGPU޲͚ͷ ίϚϯυ ϏσΦϝϞϦ Χʔωϧۭؒ Linux Ϩϯμʔϊʔυ ϓϥΠϚϦϊʔυ libdrm ඳ͍ͯ ΋͠ը໘ʹද͕ࣔͨ͠Δϓϩηε͕ ϗετʹ1͔ͭ͠ͳ͍ͳΒ

Slide 18

Slide 18 text

ϏσΦϝϞϦ Χʔωϧۭؒ Ϣʔβۭؒ Linux Mesa Ϩϯμʔϊʔυ ΞϓϦέʔγϣϯ ϓϥΠϚϦϊʔυ ΋͠ը໘ʹද͕ࣔͨ͠Δϓϩηε͕ ϗετʹ1͔ͭ͠ͳ͍ͳΒ Q. ͜Ε͕Ͱ͖ΔഺͰ͸ libdrm ͜ΕΛදࣔͯ͠ ϋʔυ΢ΣΞඇґଘͷ GPUͷૢ࡞ ಛఆͷGPU޲͚ͷ ίϚϯυ

Slide 19

Slide 19 text

VK_KHR_display A. Ͱ͖Δ

Slide 20

Slide 20 text

Instance Extensions: count = 20 =============================== VK_EXT_acquire_drm_display : extension revision 1 VK_EXT_acquire_xlib_display : extension revision 1 VK_EXT_debug_report : extension revision 10 VK_EXT_debug_utils : extension revision 2 VK_EXT_direct_mode_display : extension revision 1 VK_EXT_display_surface_counter : extension revision 1 VK_KHR_device_group_creation : extension revision 1 VK_KHR_display : extension revision 23 VK_KHR_external_fence_capabilities : extension revision 1 VK_KHR_external_memory_capabilities : extension revision 1 VK_KHR_external_semaphore_capabilities : extension revision 1 VK_KHR_get_display_properties2 : extension revision 1 VK_KHR_get_physical_device_properties2 : extension revision 2 VK_KHR_get_surface_capabilities2 : extension revision 1 VK_KHR_portability_enumeration : extension revision 1 VK_KHR_surface : extension revision 25 VK_KHR_surface_protected_capabilities : extension revision 1 VK_KHR_wayland_surface : extension revision 6 VK_KHR_xcb_surface : extension revision 6 ͜Ε

Slide 21

Slide 21 text

#include #include #include #include #include int main( int argc, const char *argv[] ) { #ifdef VULKAN_HPP_DISPATCH_LOADER_DYNAMIC // Vulkan-Hpp͔ΒvkCreateInstanceΛݺ΂ΔΑ͏ʹ͢Δ vk::DynamicLoader dl; PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = dl.getProcAddress( "vkGetInstanceProcAddr" ); VULKAN_HPP_DEFAULT_DISPATCHER.init( vkGetInstanceProcAddr ); #endif const auto app_info = vk::ApplicationInfo() // ΞϓϦέʔγϣϯͷ໊લ .setPApplicationName( argc ? argv[ 0 ] : "my_application" ) // ΞϓϦέʔγϣϯͷόʔδϣϯ .setApplicationVersion( VK_MAKE_VERSION(1, 0, 0) ) // Τϯδϯͷ໊લ

Slide 22

Slide 22 text

const std::vector< const char * > layers{ "VK_LAYER_KHRONOS_validation" }; // ҎԼͷ֦ுΛ࢖͏ const std::vector< const char* > exts{ "VK_KHR_surface", // දࣔ͢ΔҝͷඳըΛߦ͏ "VK_KHR_display" // σΟεϓϨΠͷૢ࡞Λߦ͏ }; // ΠϯελϯεΛ࡞੒ auto instance = vk::createInstanceUnique( vk::InstanceCreateInfo() // ΞϓϦέʔγϣϯͷ৘ใΛࢦఆ .setPApplicationInfo( &app_info ) // ࢖༻͢ΔϨΠϠʔΛࢦఆ .setPEnabledLayerNames( layers ) // ࢖༻͢Δ֦ுΛࢦఆ .setPEnabledExtensionNames( exts ) );

Slide 23

Slide 23 text

const auto devices = instance->enumeratePhysicalDevices(); for( const auto &device: devices ) { // GPUͷ৘ใΛऔಘ const auto props = device.getProperties(); // ͜ͷGPUʹܨ͕͍ͬͯΔσΟεϓϨΠͷ৘ใΛऔಘ const auto displays = device.getDisplayPropertiesKHR(); for( const auto &display: displays ) { std::cout << "GPU " << props.deviceName << " ʹσΟεϓϨΠ " << display.displayName << " ͕઀ଓ͞Ε͍ͯΔ" << std::endl; std::cout << " ࠷େղ૾౓ : " << display.physicalResolution.width << "x" << display.physicalResolution.height << std::endl; // σΟεϓϨΠͷରԠϞʔυΛऔಘ const auto modes = device.getDisplayModePropertiesKHR( display.display ); for( const auto &mode: modes ) { std::cout << " ରԠϞʔυ : " << GPUͱσΟεϓϨΠͷ৘ใΛऔಘ

Slide 24

Slide 24 text

for( const auto &display: displays ) { std::cout << "GPU " << props.deviceName << " ʹσΟεϓϨΠ " << display.displayName << " ͕઀ଓ͞Ε͍ͯΔ" << std::endl; std::cout << " ࠷େղ૾౓ : " << display.physicalResolution.width << "x" << display.physicalResolution.height << std::endl; // σΟεϓϨΠͷରԠϞʔυΛऔಘ const auto modes = device.getDisplayModePropertiesKHR( display.display ); for( const auto &mode: modes ) { std::cout << " ରԠϞʔυ : " << mode.parameters.visibleRegion.width << "x" << mode.parameters.visibleRegion.height << "@" << float( mode.parameters.refreshRate ) / 1000.f << "Hz" << std::endl; } } } ར༻ՄೳͳදࣔϞʔυΛऔಘ

Slide 25

Slide 25 text

$ ./src/example/list_displays/list_displays Vulkan 1.3.224 GPU NVIDIA GeForce RTX 2070 ʹσΟεϓϨΠ Asustek Computer Inc PA32UCX (DP-0) ͕઀ଓ͞Ε͍ͯΔ ࠷େղ૾౓ : 3840x2160 ରԠϞʔυ : [email protected] ରԠϞʔυ : 3840x2160@50Hz ରԠϞʔυ : [email protected] ରԠϞʔυ : 3840x2160@25Hz ରԠϞʔυ : [email protected] ରԠϞʔυ : [email protected] ରԠϞʔυ : [email protected]

Slide 26

Slide 26 text

// Πϯελϯε͕αϙʔτ͢ΔVulkanͷόʔδϣϯΛऔಘ const auto version = vk::enumerateInstanceVersion(); std::cout << "Vulkan " << VK_VERSION_MAJOR( version ) << "." << VK_VERSION_MINOR( version ) << "." << VK_VERSION_PATCH( version ) << std::endl; // 1ݸ໨ͷGPUʹܨ͕͍ͬͯΔ1ݸ໨ͷσΟεϓϨΠΛ1ݸ໨ͷදࣔϞʔυͰ࢖͏ const auto devices = instance->enumeratePhysicalDevices(); if( devices.empty() ) std::abort(); const auto displays = devices[ 0 ].getDisplayPropertiesKHR(); if( displays.empty() ) std::abort(); const auto modes = devices[ 0 ].getDisplayModePropertiesKHR( displays[ 0 ].display ); if( modes.empty() ) std::abort(); // ͜ͷ৚݅ͰαʔϑΣεΛ࡞Δ const auto surface = instance->createDisplayPlaneSurfaceKHRUnique( vk::DisplaySurfaceCreateInfoKHR() .setDisplayMode( modes[ 0 ].displayMode ) .setImageExtent( modes[ 0 ].parameters.visibleRegion )

Slide 27

Slide 27 text

if( modes.empty() ) std::abort(); // ͜ͷ৚݅ͰαʔϑΣεΛ࡞Δ const auto surface = instance->createDisplayPlaneSurfaceKHRUnique( vk::DisplaySurfaceCreateInfoKHR() .setDisplayMode( modes[ 0 ].displayMode ) .setImageExtent( modes[ 0 ].parameters.visibleRegion ) ); // αʔϑΣεͰར༻ՄೳͳϐΫηϧϑΥʔϚοτΛऔಘ͢Δ const auto available_formats = devices[ 0 ].getSurfaceFormatsKHR( *surface ); for( const auto &format: available_formats ) { std::cout << "ར༻ՄೳͳϑΥʔϚοτ : " << nlohmann::json( format ) << std::endl; } // ཉ͍͠ϐΫηϧύοΩϯάํ๏ const std::vector< vk::Format > expected_formats{ vk::Format::eA2B10G10R10UnormPack32, // 30bit BGR vk::Format::eA8B8G8R8UnormPack32, // 24bit BGR

Slide 28

Slide 28 text

const std::vector< vk::Format > expected_formats{ vk::Format::eA2B10G10R10UnormPack32, // 30bit BGR vk::Format::eA8B8G8R8UnormPack32, // 24bit BGR vk::Format::eB8G8R8A8Unorm, // 24bit RGB vk::Format::eR5G6B5UnormPack16 // 16bit RGB }; // ৭ۭ͕ؒsRGBͰ্هͷํ๏ͰύοΩϯά͞ΕͨϑΥʔϚοτΛ୳͢ vk::Format selected_format = vk::Format::eUndefined; for( const auto &e: expected_formats ) { if( std::find_if( available_formats.begin(), available_formats.end(), [e]( const auto &f ) { return f.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear && f.format == e; } ) != available_formats.end() ) { selected_format = e; break; } }

Slide 29

Slide 29 text

// αʔϑΣεͷ৘ใΛऔಘ const auto surface_capabilities = devices[ 0 ].getSurfaceCapabilitiesKHR( *surface ); std::cout << "αʔϑΣεͷ࠷খΠϝʔδ਺ : " << surface_capabilities.minImageCount << std::endl; std::cout << "αʔϑΣεͷ࠷େΠϝʔδ਺ : " << surface_capabilities.maxImageCount << std::endl; // σόΠεʹඋΘ͍ͬͯΔΩϡʔΛऔಘ const auto queue_props = devices[ 0 ].getQueueFamilyProperties(); uint32_t queue_family_index = 0u; // ඳըཁٻΛड͚෇͚ΔΩϡʔΛ୳͢ for( uint32_t i = 0; i < queue_props.size(); ++i ) { if( queue_props[ i ].queueFlags & vk::QueueFlagBits::eGraphics ) { queue_family_index = i; break; } } αʔϑΣε্Ͱར༻ՄೳͳΠϝʔδͷ਺Λऔಘ

Slide 30

Slide 30 text

ϏσΦϝϞϦ Χʔωϧۭؒ Ϣʔβۭؒ Linux Mesa ΞϓϦέʔγϣϯ දࣔ ϋʔυ΢ΣΞඇґଘͷ GPUͷૢ࡞ ಛఆͷGPU޲͚ͷ ίϚϯυ ඳը ϓϥΠϚϦϊʔυ ੾Γସ͑ දࣔத libdrm ඳ͖͔͚͕ දࣔ͞Εͯ͸͍͚ͳ͍ αʔϑΣε͸ 2ը໘෼Ҏ্ͷαΠζͰ ֬อ͞ΕΔ ඳ͖ऴΘͬͨΒ දࣔ͢ΔΠϝʔδΛ ੾Γସ͑Δ

Slide 31

Slide 31 text

// σόΠεʹඋΘ͍ͬͯΔΩϡʔΛऔಘ const auto queue_props = devices[ 0 ].getQueueFamilyProperties(); uint32_t queue_family_index = 0u; // ඳըཁٻΛड͚෇͚ΔΩϡʔΛ୳͢ for( uint32_t i = 0; i < queue_props.size(); ++i ) { if( queue_props[ i ].queueFlags & vk::QueueFlagBits::eGraphics ) { queue_family_index = i; break; } } // ҎԼͷσόΠε֦ுΛ࢖͏ std::vector< const char* > dexts{ "VK_KHR_swapchain" // εϫοϓνΣΠϯΛ࢖͏ }; const float priority = 0.0f; // ඳըཁٻΛड͚෇͚ΔΩϡʔΛ1͍ͭͩ͘͞ std::vector< vk::DeviceQueueCreateInfo > queues{ ෺ཧσόΠε શछରԠ શछରԠ ܭࢉઐ༻ ܭࢉઐ༻ సૹઐ༻ Ωϡʔ ͜͜ʹίϚϯυΛྲྀ͢ͱ GPUͰίϚϯυ͕ ࣮ߦ͞ΕΔ

Slide 32

Slide 32 text

// σόΠεʹඋΘ͍ͬͯΔΩϡʔΛऔಘ const auto queue_props = devices[ 0 ].getQueueFamilyProperties(); uint32_t queue_family_index = 0u; // ඳըཁٻΛड͚෇͚ΔΩϡʔΛ୳͢ for( uint32_t i = 0; i < queue_props.size(); ++i ) { if( queue_props[ i ].queueFlags & vk::QueueFlagBits::eGraphics ) { queue_family_index = i; break; } } // ҎԼͷσόΠε֦ுΛ࢖͏ std::vector< const char* > dexts{ "VK_KHR_swapchain" // εϫοϓνΣΠϯΛ࢖͏ }; const float priority = 0.0f; // ඳըཁٻΛड͚෇͚ΔΩϡʔΛ1͍ͭͩ͘͞ std::vector< vk::DeviceQueueCreateInfo > queues{ ෺ཧσόΠε GPUͷৼΔ෣͍ͷઃఆ ࿦ཧσόΠε ࢖͏෺ཧσόΠε ࢖͏Ωϡʔ GPUͷઃఆ ࿦ཧσόΠε + + =

Slide 33

Slide 33 text

const float priority = 0.0f; // ඳըཁٻΛड͚෇͚ΔΩϡʔΛ1͍ͭͩ͘͞ std::vector< vk::DeviceQueueCreateInfo > queues{ vk::DeviceQueueCreateInfo() .setQueueFamilyIndex( queue_family_index ) .setQueuePriorities( priority ) }; // ࿦ཧσόΠεΛ࡞Δ auto device = devices[ 0 ].createDeviceUnique( vk::DeviceCreateInfo() // ͜ͷΩϡʔΛ࢖͏ .setQueueCreateInfos( queues ) // ͜ͷσόΠε֦ுΛ࢖͏ .setPEnabledExtensionNames( dexts ) ); // σόΠε͔ΒΩϡʔΛऔಘ auto queue = device->getQueue( queue_family_index, 0u );

Slide 34

Slide 34 text

// εϫοϓνΣʔϯΛ࡞Δ const auto swapchain = device->createSwapchainKHRUnique( vk::SwapchainCreateInfoKHR() // ͜ͷαʔϑΣεʹඳը݁ՌΛૹΔ .setSurface( *surface ) // εϫοϓνΣʔϯͷΠϝʔδͷ਺ .setMinImageCount( surface_capabilities.minImageCount ) // εϫοϓνΣʔϯͷΠϝʔδͷϑΥʔϚοτ .setImageFormat( selected_format ) // εϫοϓνΣʔϯͷΠϝʔδͷ৭ۭؒ .setImageColorSpace( vk::ColorSpaceKHR::eSrgbNonlinear ) // εϫοϓνΣʔϯͷΠϝʔδͷେ͖͞ .setImageExtent( surface_capabilities.currentExtent ) // ϨΠϠʔ͸1ͭ .setImageArrayLayers( 1u ) // εϫοϓνΣʔϯͷΠϝʔδ͸సૹઌʹ΋࢖͑Δඞཁ͕͋Δ .setImageUsage( vk::ImageUsageFlagBits::eTransferDst αʔϑΣεͷͲͷΠϝʔδ͕දࣔத͔Λอ࣋͢Δ දࣔதͩͬͨΠϝʔδ͕දࣔதͰͳ͘ͳͬͨΒڭ͑ͯ͘ΕΔ εϫοϓνΣΠϯ

Slide 35

Slide 35 text

// εϫοϓνΣʔϯͷΠϝʔδΛऔಘ͢Δ const auto swapchain_images = device- >getSwapchainImagesKHR( *swapchain ); std::cout << "εϫοϓνΣΠϯͷΠϝʔδͷ਺ : " << swapchain_images.size() << std::endl; // ίϚϯυϓʔϧΛ࡞Δ const auto command_pool = device->createCommandPoolUnique( vk::CommandPoolCreateInfo() .setQueueFamilyIndex( 0u ) ); { // ίϚϯυόοϑΝΛ࡞Δ const auto command_buffers = device->allocateCommandBuffersUnique( vk::CommandBufferAllocateInfo() .setCommandPool( *command_pool ) .setLevel( vk::CommandBufferLevel::ePrimary ) .setCommandBufferCount( 1u ) εϫοϓνΣΠϯ͔ΒશͯͷΠϝʔδΛऔಘ͠

Slide 36

Slide 36 text

// εϫοϓνΣΠϯͷΠϝʔδΛ੨ͰృΓͭͿ͢ command_buffer->clearColorImage( image, // ͜ͷΠϝʔδΛ vk::ImageLayout::eTransferDstOptimal, // ੨ vk::ClearColorValue() .setFloat32( std::array< float, 4u >{ 0.f, 0.f, 1.f, 1.f } ), { vk::ImageSubresourceRange() // ৭Λॻ͖׵͑Δ .setAspectMask( vk::ImageAspectFlagBits::eColor ) // 0൪໨ͷϛοϓϨϕϧ .setBaseMipLevel( 0u ) .setLevelCount( 1u ) // 0൪໨ͷϨΠϠʔ .setBaseArrayLayer( 0u ) .setLayerCount( 1u ) } ); ੨ͰృΓͭͿ͢ίϚϯυΛ༻ҙ

Slide 37

Slide 37 text

.setAspectMask( vk::ImageAspectFlagBits::eColor ) .setBaseMipLevel( 0u ) .setLevelCount( 1u ) .setBaseArrayLayer( 0u ) .setLayerCount( 1u ) ) } ); } // ίϚϯυόοϑΝͷه࿥ΛऴΘΔ command_buffer->end(); // ίϚϯυόοϑΝΛΩϡʔʹྲྀ͢ queue.submit( vk::SubmitInfo() .setCommandBufferCount( 1u ) .setPCommandBuffers( &*command_buffer ), VK_NULL_HANDLE ); // Ωϡʔʹྲྀͨ͠ίϚϯυ͕׬ྃ͢Δ·Ͱ଴ͭ queue.waitIdle(); } ը໘ʹදࣔΛ࢝ΊΔલʹ αʔϑΣεΛ੨ͰృΓͭͿ͓ͯ͘͠ ίϚϯυΛΩϡʔʹྲྀͯ͠׬ྃΛ଴ͭ

Slide 38

Slide 38 text

uint32_t current_frame = 0u; while( 1 ) { const auto begin_time = std::chrono::high_resolution_clock::now(); // εϫοϓνΣΠϯ͔Β࣍ʹॻ͘΂͖ΠϝʔδͷindexΛ໯͏ std::uint32_t image_index = device->acquireNextImageKHR( // ͜ͷεϫοϓνΣʔϯ͔Β *swapchain, // Πϝʔδ͕໯͑Δ·Ͱ͍͘ΒͰ΋଴ͭ std::numeric_limits< std::uint64_t >::max(), // Πϝʔδ͕ද͔ࣔΒ֎ΕͨΒ͜ͷηϚϑΥʹ௨஌ *image_acquired[ current_frame ], VK_NULL_HANDLE ).value; // ΠϝʔδΛॻ͖׵͑ͳ͍Ͱ͙͢ʹදࣔʹ·Θ͢ if( queue.presentKHR( vk::PresentInfoKHR() εϫοϓνΣΠϯ͔Β ඳ͍ͯ΋େৎ෉ͳαʔϑΣεͷΠϝʔδͷΠϯσοΫεΛ໯͍

Slide 39

Slide 39 text

VK_NULL_HANDLE ).value; // ΠϝʔδΛॻ͖׵͑ͳ͍Ͱ͙͢ʹදࣔʹ·Θ͢ if( queue.presentKHR( vk::PresentInfoKHR() .setWaitSemaphoreCount( 1u ) // ͜ͷηϑΥʹ௨஌͕དྷΔ·Ͱ଴͔ͬͯΒ .setPWaitSemaphores( &*image_acquired[ current_frame ] ) .setSwapchainCount( 1 ) // ͜ͷεϫοϓνΣʔϯͷ .setPSwapchains( &*swapchain ) // ͜ͷΠϝʔδΛαʔϑΣεʹૹΔ .setPImageIndices( &image_index ) ) != vk::Result::eSuccess ) std::abort(); ++current_frame; current_frame %= swapchain_images.size(); // 1ϑϨʔϜͷද͕ࣔ࣌ؒܦա͢Δ·Ͱ଴ͭ ಺༰Λॻ͖׵͑ͳ͍Ͱ͙͢ʹදࣔʹ·Θ͢

Slide 40

Slide 40 text

// ͜ͷηϑΥʹ௨஌͕དྷΔ·Ͱ଴͔ͬͯΒ .setPWaitSemaphores( &*image_acquired[ current_frame ] ) .setSwapchainCount( 1 ) // ͜ͷεϫοϓνΣʔϯͷ .setPSwapchains( &*swapchain ) // ͜ͷΠϝʔδΛαʔϑΣεʹૹΔ .setPImageIndices( &image_index ) ) != vk::Result::eSuccess ) std::abort(); ++current_frame; current_frame %= swapchain_images.size(); // 1ϑϨʔϜͷද͕ࣔ࣌ؒܦա͢Δ·Ͱ଴ͭ const auto end_time = std::chrono::high_resolution_clock::now(); const auto elapsed_time = end_time - begin_time; if( elapsed_time < frame_time ) { const auto sleep_for = frame_time - elapsed_time; std::this_thread::sleep_for( sleep_for ); } } ͜ΕΛσΟεϓϨΠͷϦϑϨογϡϨʔτʹಉظͯ͠܁Γฦ͢

Slide 41

Slide 41 text

https://speakerdeck.com/fadis/imadokifalsevulkan ৄ͍͠Vulkanͷ࢖͍ํ͸ Ҏલղઆͨ͠΍͕ͭ͋Δ͔Β ͦͬͪΛݟͯͶ

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

UIΛඳ͖͍ͨ

Slide 45

Slide 45 text

UIͷத਎͸ Πϕϯτ͕ى͜Βͳ͍ݶΓ มԽ͠ͳ͍ UIͷ֎͸ ຖϑϨʔϜಈ͔͘΋͠Εͳ͍͚Ͳ

Slide 46

Slide 46 text

ϏσΦϝϞϦ ΞϓϦέʔγϣϯ ຖϑϨʔϜߦ͏ ಺༰͕มΘ͚ͬͨ࣌ͩߦ͏ ίϐʔ ඳը ඳը දࣔ UIͷத਎͚ͩผͷΠϝʔδʹඳը UIͷத਎͕มԽ͚ͨ࣌ͩ͠ߋ৽͠Α͏

Slide 47

Slide 47 text

จࣈ จࣈจࣈจࣈ จࣈจࣈจࣈจࣈจࣈจࣈจࣈจࣈ จࣈจࣈจࣈจࣈจࣈจࣈ จࣈจࣈจࣈ จࣈจࣈจࣈจࣈจࣈจࣈจࣈจࣈ จࣈจࣈจࣈจࣈจࣈจࣈ จࣈ ০Βͳ͍ΠϚυΩͷUIͷߏ੒ཁૉ ௕ํܗ จࣈ ه߸ ը૾

Slide 48

Slide 48 text

௕ํܗ จࣈ ه߸ ը૾ SVG౳ͷ ϕΫλը૾ TrueType౳ͷ ςΫενϟΛషͬͨ ςΫενϟΛష͍ͬͯͳ͍ ௕ํܗ

Slide 49

Slide 49 text

௕ํܗ จࣈ ه߸ ը૾ SVG౳ͷ ϕΫλը૾ TrueType౳ͷ ςΫενϟΛషͬͨ ςΫενϟΛష͍ͬͯͳ͍ ௕ํܗ

Slide 50

Slide 50 text

௕ํܗ ΛGPUͰେྔʹඳ͖͍ͨ

Slide 51

Slide 51 text

GPU CPU ௕ํܗ ͷඳըཁٻΛେྔʹ౤͛Δͱ CPUଆͷෛ୲͕όΧʹͳΒͳ͍ ௕ํܗ ͸Α࣍ GPU͸εϨου਺ͰੑೳΛՔ͙ͷͰ খ͍͞ඳըཁٻͰ͸ੑೳ͕Ͱͳ͍

Slide 52

Slide 52 text

CPU͔Β΋GPU͔Β΋ݟ͑ΔϝϞϦ GPU CPU ௕ํܗ × 500 Πϯελϯγϯά 1ίϚϯυͰಉ͡τϙϩδͷਤܗΛେྔʹඳ͘ ௕ํܗ0ͷ഑ஔ ௕ํܗ1ͷ഑ஔ ௕ํܗ2ͷ഑ஔ ௕ํܗ3ͷ഑ஔ ⋮

Slide 53

Slide 53 text

struct rect_info { vec4 color; u16vec2 offset; u16vec2 extent; u16vec2 semantic; uint16_t texid; uint16_t depth; }; layout(std430,binding = 0) buffer Uniforms { mat4 world_matrix; rect_info rects[ 65536 ]; float scale_factor; } uniforms; CPU͔Βॻ͍ͯGPUͰಡΉ৘ใͷߏ଄ମ ϐΫηϧ࠲ඪܥ΁ͷม׵ߦྻ (−1, − 1) (−1,1) (1,1) (1, − 1) VulkanͷεΫϦʔϯ࠲ඪܥ ϐΫηϧ࠲ඪܥ (0,2040) (0,0) (3840,0) (3840,2040)

Slide 54

Slide 54 text

struct rect_info { vec4 color; u16vec2 offset; u16vec2 extent; u16vec2 semantic; uint16_t texid; uint16_t depth; }; layout(std430,binding = 0) buffer Uniforms { mat4 world_matrix; rect_info rects[ 65536 ]; float scale_factor; } uniforms; CPU͔Βॻ͍ͯGPUͰಡΉ৘ใͷߏ଄ମ ௕ํܗͷ৘ใͷ഑ྻ ͜ͷ৭Ͱ ͜ͷϐΫηϧ͔Β ͜ͷαΠζͷ ௕ํܗΛඳ͍ͯ (0,2040) (0,0) (3840,0) (3840,2040)

Slide 55

Slide 55 text

struct rect_info { vec4 color; u16vec2 offset; u16vec2 extent; u16vec2 semantic; uint16_t texid; uint16_t depth; }; layout(std430,binding = 0) buffer Uniforms { mat4 world_matrix; rect_info rects[ 65536 ]; float scale_factor; } uniforms; Ұ౓ͷDrawͰ࠷େ65536ݸͷ Λඳ͘ ௕ํܗ ͷ਺͕65536ݸΛ௒͑Δ৔߹͸ෳ਺ͷίϚϯυʹ෼͚Δ ௕ํܗ

Slide 56

Slide 56 text

void main() { vec4 pixel_pos = vec4( ( input_position.x * float( uint( uniforms.rects[ gl_InstanceIndex ].extent.x ) ) + float( uint( uniforms.rects[ gl_InstanceIndex ].offset.x ) ) ) * uniforms.scale_factor, ( input_position.y * float( uint( uniforms.rects[ gl_InstanceIndex ].extent.y ) ) + float( uint( uniforms.rects[ gl_InstanceIndex ].offset.y ) ) ) * uniforms.scale_factor, float( 65535 - uint( uniforms.rects[ gl_InstanceIndex ].depth ) ) / 65536.f, 1.0 ); gl_Position = uniforms.world_matrix * pixel_pos; output_color = vec4( uniforms.rects[ gl_InstanceIndex ].color.r, uniforms.rects[ gl_InstanceIndex ].color.g, uniforms.rects[ gl_InstanceIndex ].color.b, 1.0 ); Πϯελϯεຖʹ͜ͷ஋͕มΘΔ (0,1) (0,0) (1,0) (1,1) ΛඞཁͳαΠζʹͯ͠ εΫϦʔϯ࠲ඪܥʹม׵ͯ͠ϥελϥΠβ΁

Slide 57

Slide 57 text

void rect_renderer::add_rectangle_internal( const vk::Rect2D &rect, const std::array< float, 4u > &color, std::uint16_t depth, std::uint16_t semantic_id, std::uint16_t texid ) { const auto instance_id = instance_count++; uniforms_host.rects[ instance_id ].offset[ 0 ] = rect.offset.x * scale; uniforms_host.rects[ instance_id ].offset[ 1 ] = rect.offset.y * scale; uniforms_host.rects[ instance_id ].extent[ 0 ] = rect.extent.width * scale; uniforms_host.rects[ instance_id ].extent[ 1 ] = rect.extent.height * scale; uniforms_host.rects[ instance_id ].color = glm::vec4( color[ 0 ], color[ 1 ], color[ 2 ], color[ 3 ] ); uniforms_host.rects[ instance_id ].depth = depth; uniforms_host.rects[ instance_id ].texid = texid; uniforms_host.rects[ instance_id ].semantic[ 0 ] = 0; uniforms_host.rects[ instance_id ].semantic[ 1 ] = semantic_id; } ௕ํܗͷ௥ՃΛཁٻ͞ΕͨΒ GPU͔ΒಡΉߏ଄ମʹ৘ใΛੵΜͰ͓͘

Slide 58

Slide 58 text

std::random_device seedgen; std::mt19937 rng( seedgen() ); std::uniform_int_distribution<> xdist( 0u, 3839u ); std::uniform_int_distribution<> ydist( 0u, 2159u ); std::uniform_int_distribution<> cdist( 0u, 0xFFFFFFu ); std::uniform_int_distribution<> ddist( 0u, 32767u ); for( std::size_t i = 0u; i != 1024u; ++i ) { auto x0 = xdist( rng ); auto x1 = xdist( rng ); if( x0 > x1 ) std::swap( x0, x1 ); auto y0 = ydist( rng ); auto y1 = ydist( rng ); if( y0 > y1 ) std::swap( y0, y1 ); auto c = cdist( rng ); auto d = ddist( rng ); window.add_rectangle( vk::Rect2D{ vk::Offset2D{ x0, y0 }, vk::Extent2D{ x1 - x0, y1 - y0 } }, gct::srgb_oetf( gct::html_color( c ) ), d, true, 0u, 0u, 0u ); } ཚ਺ͰܾΊͨҐஔʹཚ਺ͰܾΊͨ৭ͷ Λඳ͘ ௕ํܗ

Slide 59

Slide 59 text

void rect_renderer::draw( gct::command_buffer_recorder_t &recorder ) { recorder.bind_pipeline( pipeline ); recorder.bind_descriptor_set( vk::PipelineBindPoint::eGraphics, pipeline_layout, descriptor_set ); recorder.bind_vertex_buffer( shape.vertex_buffer ); recorder->draw( shape.vertex_count, instance_count, 0, 0 ); } ͜ͷඳ͖ํͰ ͔͜͜Β ߏ଄ମͷσʔλΛरͬͯ (0,1) (0,0) (1,0) (1,1) Λ 6௖఺ 1024ݸ

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

௕ํܗ จࣈ ه߸ ը૾ SVG౳ͷ ϕΫλը૾ TrueType౳ͷ ςΫενϟΛషͬͨ ςΫενϟΛష͍ͬͯͳ͍ ௕ํܗ ࣍͸͜Ε

Slide 62

Slide 62 text

+ = GPUͰϝογϡʹϥελը૾ΛషΔͳΒ ςΫενϟαϯϓϦϯά

Slide 63

Slide 63 text

flat layout (location = 0) in vec4 input_color; flat layout (location = 1) in uvec2 input_semantic; flat layout (location = 2) in uint input_texid; layout (location = 3) in vec2 input_texcoord; layout (location = 0) out vec4 output_color; layout (location = 1) out vec2 output_semantic; layout(binding = 1) uniform sampler2D tex[ 16 ]; void main() { if( input_texid == 0 ) { if( input_color.a == 0.0 ) { discard; } output_color = input_color; } else { vec4 sampled = texture( tex[ input_texid - 1 ], input_texcoord ); if( sampled.a == 0.0 ) { discard; } output_color = sampled; } output_semantic = input_semantic; } input_texid ͕0Ͱͳ͚Ε͹ -1൪໨ͷςΫενϟ͔Β৭ΛऔΔ input_texid

Slide 64

Slide 64 text

for( const auto &image: input_images ) { updates.push_back( gct::write_descriptor_set_t() .set_basic( (*descriptor_set)[ "tex" ] .setDstArrayElement( tex_id ) .setDescriptorCount( 1 ) ) .add_image( gct::descriptor_image_info_t() .set_sampler( sampler ) .set_image_view( image ) .set_basic( vk::DescriptorImageInfo() .setImageLayout( vk::ImageLayout::eShaderReadOnlyOptimal ) ) ) ); ++tex_id; } canvasʹηοτ͞ΕͨΠϝʔδΛ ςΫενϟαϯϓϥʔʹ݁ͼ͚ͭΔ

Slide 65

Slide 65 text

gct::canvas window( device, allocator, pipeline_cache, descriptor_pool, wvs, wfs, vk::Extent2D{ width, height }, std::array< float, 4u >{ 0.f, 0.f, 0.f, 0.f }, {}, { image->get_view( gct::image_view_create_info_t() .set_basic( vk::ImageViewCreateInfo() .setSubresourceRange( vk::ImageSubresourceRange() .setAspectMask( vk::ImageAspectFlagBits::eColor ) .setBaseMipLevel( 0 ) .setLevelCount( image->get_props().get_basic().mipLevels ) .setBaseArrayLayer( 0 ) .setLayerCount( image->get_props().get_basic().arrayLayers ) ) .setViewType( gct::to_image_view_type( image->get_props().get_basic().imageType ) ) .setFormat( vk::Format::eR8G8B8A8Srgb ) ) .rebuild_chain() ) } ); canvasͷҾ਺ʹΠϝʔδΛ౉͢

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

gct::canvas window( device, allocator, pipeline_cache, descriptor_pool, wvs, wfs, vk::Extent2D{ 640u, 300u }, std::array< float, 4u >{ 0.f, 0.f, 0.f, 0.f }, {}, { icon->get_view( gct::image_view_create_info_t() .set_basic( vk::ImageViewCreateInfo() .setSubresourceRange( vk::ImageSubresourceRange() .setAspectMask( vk::ImageAspectFlagBits::eColor ) .setBaseMipLevel( 0 ) .setLevelCount( icon->get_props().get_basic().mipLevels ) .setBaseArrayLayer( 0 ) 640x300ͷ΢Οϯυ΢Λ࡞ͬͯ

Slide 68

Slide 68 text

{ icon->get_view( gct::image_view_create_info_t() .set_basic( vk::ImageViewCreateInfo() .setSubresourceRange( vk::ImageSubresourceRange() .setAspectMask( vk::ImageAspectFlagBits::eColor ) .setBaseMipLevel( 0 ) .setLevelCount( icon->get_props().get_basic().mipLevels ) .setBaseArrayLayer( 0 ) .setLayerCount( icon->get_props().get_basic().arrayLayers ) ) .setViewType( gct::to_image_view_type( icon->get_props().get_basic().imageType ) ) .setFormat( vk::Format::eR8G8B8A8Srgb ) ) .rebuild_chain() ) } ); ࢖͏ը૾Ληοτͯ͠

Slide 69

Slide 69 text

window.add_rectangle( vk::Rect2D{ vk::Offset2D{ 0, 0 }, vk::Extent2D{ 640, 300 } }, gct::srgb_oetf( gct::html_color( 0xf0f8ff ) ), 0u, true, 0u, 0u, 0u ); window.add_rectangle( vk::Rect2D{ vk::Offset2D{ 95, 50 }, vk::Extent2D{ 200, 70 } }, gct::srgb_oetf( gct::html_color( 0xc0c0c0 ) ), 1u, true, 0u, 0u, 1u ); window.add_rectangle( vk::Rect2D{ vk::Offset2D{ 345, 50 }, vk::Extent2D{ 200, 70 } }, gct::srgb_oetf( gct::html_color( 0x4169e1 ) ), 1u, true, 0u, 0u, 2u ); window.add_rectangle( vk::Rect2D{ vk::Offset2D{ 0, 0 }, vk::Extent2D{ 640, 300 } }, gct::srgb_oetf( gct::html_color( 0x000000 ) ), 1u, false, 1u, 0u, 0u ); window.add_rectangle( vk::Rect2D{ vk::Offset2D{ 50, 150 }, vk::Extent2D{ 128, 128 } }, Ϙλϯͱ͔ฒ΂ͯ

Slide 70

Slide 70 text

desktop.push_back( std::shared_ptr< gct::canvas >( new gct::canvas( device, allocator, pipeline_cache, descriptor_pool, wvs, dfs, vk::Extent2D{ width, height }, gct::srgb_oetf( gct::html_color( 0x008080 ) ), {}, { window.get_color()->get_view( vk::ImageAspectFlagBits::eColor ), } ) ) ); desktop.back()->add_rectangle( vk::Rect2D{ vk::Offset2D{ ( width - 640u ) / 2u, ( height - 300u ) / 2u }, vk::Extent2D{ 640, 300 } }, gct::srgb_oetf( gct::html_color( 0x000000 ) ), 1u, true, 0u, 1u, 0u ); canvasʹ͸ผͷcanvasͷඳը݁ՌΛ ೖྗͱͯ͠౉ͤΔ

Slide 71

Slide 71 text

No content

Slide 72

Slide 72 text

௕ํܗ จࣈ ه߸ ը૾ SVG౳ͷ ϕΫλը૾ TrueType౳ͷ ςΫενϟΛషͬͨ ςΫενϟΛష͍ͬͯͳ͍ ௕ํܗ ࣍͸͜Ε

Slide 73

Slide 73 text

จࣈ͸ 2࣍BézierεϓϥΠϯۂઢͰ දݱ͞ΕͨϕΫλը૾ TrueType

Slide 74

Slide 74 text

PathFinder https://github.com/servo/pathfinder ίϯϐϡʔτγΣʔμͰϥελϥΠζ NanoVG libtess2 https://github.com/memononen/libtess2 CPUͰࡾ֯ܗ෼ׂɺGPUͰඳը https://github.com/memononen/nanovg CPUͰߥ͘ࡾ֯ܗ෼ׂɺGPUͰඳըɺεςϯγϧͰमਖ਼ Cairo https://www.cairographics.org/ CPUͰϥελϥΠζ CPUͰ΍Δ GPUͰ΍Δ GPUͰૉૣ͘ϕΫλը૾Λඳ͘ͷ͸؆୯Ͱ͸ͳ͍ OpenGL༻ OpenGL༻ OpenGL༻ ͔͠΋طଘͷ࣮૷͸େମVulkanͳΞϓϦέʔγϣϯʹ૊ΈࠐΊͳ͍

Slide 75

Slide 75 text

ࣄલʹϑΥϯτΛࡾ֯ܗ෼ׂͨ͠σʔλΛ༻ҙͯ͠ ࣮ߦ࣌͸ͦΕΛͦͷ··GPUͰඳը͠Α͏

Slide 76

Slide 76 text

https://github.com/fetisov/ttf2mesh ttf2mesh TrueTypeͷ ϑΥϯτΛಡΜͰ ࡾ֯ܗ෼ׂͯ͠ ௖఺ͷϦετΛฦ͢ ϥΠϒϥϦ ͜ΕΛ࢖ͬͯ ࣄલʹϑΥϯτΛ ௖఺഑ྻʹ͠Α͏

Slide 77

Slide 77 text

ttf2meshͷ໰୊఺ Format 4ͷcmap͔͠ಡ·ͳ͍

Slide 78

Slide 78 text

Φϑηοτςʔϒϧ ςʔϒϧ ςʔϒϧ ςʔϒϧ ⋮ 55'ͷόʔδϣϯ ςʔϒϧ਺ ςʔϒϧͷछྨ νΣοΫαϜ ςʔϒϧͷઌ಄ͷҐஔ ςʔϒϧͷ௕͞ ςʔϒϧͷछྨ νΣοΫαϜ ςʔϒϧͷઌ಄ͷҐஔ ςʔϒϧͷ௕͞ ⋮ TrueTypeͷߏ଄

Slide 79

Slide 79 text

TrueTypeͷߏ଄ ςʔϒϧ໊ ಺༰ head name OS/2 maxp post ϝλσʔλ glyf άϦϑΛߏ੒͢Δۂઢͷύϥϝʔλ loca Կ൪໨ͷάϦϑ͕glyfͷ Կཁૉ໨͔Β࢝·Δ͔ cmap locaͷԿ൪໨ͷάϦϑ͕ จࣈίʔυͰݴ͏ԿͷจࣈʹରԠ͢Δ͔

Slide 80

Slide 80 text

TrueTypeͷߏ଄ - cmap DNBQͷܗࣜ ಺༰ Format 0 256ཁૉͷ഑ྻͰ8bitจࣈΛม׵ Format 2 2όΠτจࣈΛ্Ґ8bitͱԼҐ8bitʹ۠੾ͬͯ2ஈ֊Ͱม׵ Format 4 16bitͷ೚ҙͷൣғͱάϦϑͷ೚ҙͷൣғͷରԠΛ࣋ͭ UnicodeͷBMPͷൣғ͚ͩΛѻ͑Δ Format 6 ࠷େ65536ཁૉͷ഑ྻͰ16bitจࣈΛม׵ Format 8 Unicodeͷ্Ґ16bitͱԼҐ16bitͰม׵දΛ෼͚ͯ2ஈ֊Ͱม׵͢Δ Format 10 ࠷େ4294967296ཁૉͷ഑ྻͰ32bitจࣈΛม׵ Format 12 32bitͷ೚ҙͷൣғͱάϦϑͷ೚ҙͷൣғͷରԠΛ࣋ͭ UnicodeͷશͯͷจࣈΛѻ͑Δ Format 13 32bitͷ೚ҙͷൣғͱಛఆͷάϦϑͷରԠΛ࣋ͭ UnicodeͷશͯͷจࣈΛѻ͑Δ Format 14 UnicodeͷҟࣈମηϨΫλͰબ͹ΕΔจࣈͱάϦϑͷରԠΛ࣋ͭ

Slide 81

Slide 81 text

TrueTypeͷߏ଄ - cmap DNBQͷܗࣜ ಺༰ Format 0 256ཁૉͷ഑ྻͰ8bitจࣈΛม׵ Format 2 2όΠτจࣈΛ্Ґ8bitͱԼҐ8bitʹ۠੾ͬͯ2ஈ֊Ͱม׵ Format 4 16bitͷ೚ҙͷൣғͱάϦϑͷ೚ҙͷൣғͷରԠΛ࣋ͭ UnicodeͷBMPͷൣғ͚ͩΛѻ͑Δ Format 6 ࠷େ65536ཁૉͷ഑ྻͰ16bitจࣈΛม׵ Format 8 Unicodeͷ্Ґ16bitͱԼҐ16bitͰม׵දΛ෼͚ͯ2ஈ֊Ͱม׵͢Δ Format 10 ࠷େ4294967296ཁૉͷ഑ྻͰ32bitจࣈΛม׵ Format 12 32bitͷ೚ҙͷൣғͱάϦϑͷ೚ҙͷൣғͷରԠΛ࣋ͭ UnicodeͷશͯͷจࣈΛѻ͑Δ Format 13 32bitͷ೚ҙͷൣғͱಛఆͷάϦϑͷରԠΛ࣋ͭ UnicodeͷશͯͷจࣈΛѻ͑Δ Format 14 UnicodeͷҟࣈମηϨΫλͰબ͹ΕΔจࣈͱάϦϑͷରԠΛ࣋ͭ 16bitͷUnicode͔͠ѻ͑ͳ͍ݹ͍ιϑτ΢ΣΞͰ΋ϑΥϯτΛ࢖͑ΔΑ͏ʹ 
 ͜ͷܗࣜͷcmap΋Α͘ಉࠝ͞Ε͍ͯΔ ΠϚυΩͷϑΥϯτ͸େମ͜ͷܗࣜͷcmapΛؚΜͰ͍Δ

Slide 82

Slide 82 text

Unicodeͷۭؒ جຊଟݴޠ໘ #.1 ௥Ճଟݴޠ໘ 4.1 ௥Ճ׽ࣈ໘ 4*1 ୈࡾ׽ࣈ໘ 5*1 ະׂΓ౰ͯ ௥Ճಛघ༻్໘ 441 ࢲ༻໘ 0x000000 0x010000 0x020000 0x030000 0x040000 0x0F0000 0x110000 0x0E0000 16bitͰදݱͰ͖Δൣғ ೔ຊޠϑΥϯτͷจࣈ͕ ࢖͏ൣғ ttf2mesh͸ ௥Ճ׽ࣈ໘ͷ׽ࣈͷάϦϑͷ ίʔυϙΠϯτΛऔΕͳ͍

Slide 83

Slide 83 text

diff --git a/ttf2mesh.h b/ttf2mesh.h index 76e5765..abfcac9 100644 --- a/ttf2mesh.h +++ b/ttf2mesh.h @@ -145,8 +145,8 @@ struct ttf_file { int nchars; /* number of the font characters */ int nglyphs; /* number of glyphs (usually less than nchars) */ - uint16_t *chars; /* utf16 codes array with nchars length */ - uint16_t *char2glyph; /* glyph indeces array with nchars length */ + uint32_t *chars; /* utf32 codes array with nchars length */ + uint32_t *char2glyph; /* glyph indeces array with nchars length */ ttf_glyph_t *glyphs; /* array of the font glyphs with nglyphs length */ const char *filename; /* full path and file name of the font */ uint32_t glyf_csum; /* 'glyf' table checksum (used by ttf_list_fonts) */ @@ -455,7 +455,7 @@ int ttf_list_match_id(ttf_t **list, const char *requirements, ...); * @param utf16_char Unicode character * @return Glyph index in glyphs array or -1 */ -int ttf_find_glyph(const ttf_t *ttf, uint16_t utf16_char); +int ttf_find_glyph(const ttf_t *ttf, uint32_t utf32_char); UnicodeͷίʔυϙΠϯτΛ 16bit੔਺ʹಥͬࠐΜͰ͍ΔॴΛ 32bit੔਺ʹஔ͖׵͑ͯ

Slide 84

Slide 84 text

@@ -1318,6 +1335,59 @@ static int parse_fmt4(ttf_t *ttf, uint8_t *data, int dataSize, bool headers_only return TTF_DONE; } +static int parse_fmt12(ttf_t *ttf, uint8_t *data, int dataSize, bool headers_only) +{ + ttf_fmt12_t *tab; + int smgSize; + int i, j, k; + int maxGlyphID = 0; + int endGlyphID; + ttf_fmt12_smg_t *smgs; + + if (dataSize < (int)sizeof(ttf_fmt12_t)) return TTF_ERR_FMT; + tab = (ttf_fmt12_t *)data; + conv32(tab->length); + conv32(tab->numGroups); + if (tab->length > dataSize) + return TTF_ERR_FMT; Format 12ͷcmap͕͋ͬͨΒ ༏ઌతʹಡΉίʔυΛ௥Ճ

Slide 85

Slide 85 text

Format 12ରԠ൛ttf2mesh https://github.com/Fadis/ttf2mesh

Slide 86

Slide 86 text

GPUʹૹΔόΠφϦ ⋮ (−0.3515625,0.7128906) (−0.3203125,0.7988281) (−0.2734375,0.8535156) (−0.21484375,0.8847656) (−0.14453125,0.89453125) (−0.076171875,0.8847656) (−0.017578125,0.8515625) (0.029296875,0.7949219) (0.068359375,0.7128906) (0,0.6875) ⋮ 16 15 14 17 18 21 20 12 14 13 ⋮ ⋮ ⋮ ௖఺ΠϯσοΫε ௖఺഑ྻ શͯͷจࣈͷάϦϑΛ 1ͭͷόΠφϦʹؚΊ͍ͨ ͔͜͜Β ͜͜·Ͱ όΠφϦͷͲͷ෦෼͕ ͲͷάϦϑͷ෺͔Λ ผͷ৔ॴʹه࿥͢Δඞཁ͕͋Δ 1จࣈ෼

Slide 87

Slide 87 text

glTF 3DϞσϧσʔλͷϑΥʔϚοτ JSONܗࣜͷϔομͰ GPUʹૹΔόΠφϦΛ ͲͷΑ͏ʹղऍ͢΂͖͔Λهड़ ͜ͷϔομʹόΠφϦຊମΛ σʔλͱ͚ͯͬͭͨ͘͠෺ https://www.khronos.org/gltf/

Slide 88

Slide 88 text

TrueType glTF ttf2mesh

Slide 89

Slide 89 text

ttf_t *font = nullptr; ttf_load_from_file( input.c_str(), &font, false); std::vector< float > vertices; std::unordered_map< std::pair< float, float >, std::uint32_t, pair_hash > vhash; std::vector< std::uint32_t > faces; std::vector< std::tuple< unsigned int, std::uint32_t, std::uint32_t > > glyphs; std::pair< float, float > min = std::make_pair( std::numeric_limits< float >::max(), std::numeric_limits< float >::max() ); std::pair< float, float > max = std::make_pair( std::numeric_limits< float >::min(), std::numeric_limits< float >::min() ); for( unsigned int glyph_id : tq::trange( font->nglyphs ) ) { ttf_mesh_t *out; if( font->glyphs[ glyph_id ].index && font->glyphs[ glyph_id ].outline ) { if( font->glyphs[ glyph_id ].symbol >= min_code && font->glyphs[ glyph_id ].symbol <= max_code ) { auto result = ttf_glyph2mesh( ttf2meshͰϑΥϯτΛಡΉ

Slide 90

Slide 90 text

for( unsigned int glyph_id : tq::trange( font->nglyphs ) ) { ttf_mesh_t *out; if( font->glyphs[ glyph_id ].index && font->glyphs[ glyph_id ].outline ) { if( font->glyphs[ glyph_id ].symbol >= min_code && font->glyphs[ glyph_id ].symbol <= max_code ) { auto result = ttf_glyph2mesh( &font->glyphs[ glyph_id ], &out, TTF_QUALITY_LOW, TTF_FEATURE_IGN_ERR ); if( result == TTF_DONE) { std::vector< std::uint32_t > vertex_indices; for( unsigned int i = 0u; i != out->nvert; ++i ) { vertex_indices.push_back( get_index( vhash, vertices, out->vert[ i ].x, out->vert[ i ].y, align ) ); min.first = std::min( min.first, vertices[ vertex_indices.back() * 3u ] ); min.second = std::min( min.second, vertices[ vertex_indices.back() * 3u + 1u ] ); max.first = std::max( άϦϑͷ৘ใ͕ਖ਼͘͠औΕ͍ͯͯ ཉ͍͠ൣғͷจࣈͷάϦϑͩͬͨΒ

Slide 91

Slide 91 text

auto result = ttf_glyph2mesh( &font->glyphs[ glyph_id ], &out, TTF_QUALITY_LOW, TTF_FEATURE_IGN_ERR ); if( result == TTF_DONE) { std::vector< std::uint32_t > vertex_indices; for( unsigned int i = 0u; i != out->nvert; ++i ) { vertex_indices.push_back( get_index( vhash, vertices, out->vert[ i ].x, out->vert[ i ].y, align ) ); min.first = std::min( min.first, vertices[ vertex_indices.back() * 3u ] ); min.second = std::min( min.second, vertices[ vertex_indices.back() * 3u + 1u ] ); max.first = std::max( max.first, vertices[ vertex_indices.back() * 3u ] ); max.second = std::max( max.second, vertices[ vertex_indices.back() * 3u + 1u ] ); } glyphs.push_back( std::make_tuple( glyph_id, faces.size(), 0u ) ); ࡾ֯ܗ෼ׂ ௖఺഑ྻʹಉ͡࠲ඪͷ௖఺͕طʹ͋ͬͨΒͦͷΠϯσοΫεΛฦ͢ ແ͔ͬͨΒ௖఺഑ྻʹ௖఺Λ௥Ճͯͦ͠ͷΠϯσοΫεΛฦ͢

Slide 92

Slide 92 text

); min.second = std::min( min.second, vertices[ vertex_indices.back() * 3u + 1u ] ); max.first = std::max( max.first, vertices[ vertex_indices.back() * 3u ] ); max.second = std::max( max.second, vertices[ vertex_indices.back() * 3u + 1u ] ); } glyphs.push_back( std::make_tuple( glyph_id, faces.size(), 0u ) ); for( unsigned int i = 0u; i != out->nfaces; ++i ) { faces.push_back( vertex_indices[ out->faces[ i ].v1 ] ); faces.push_back( vertex_indices[ out->faces[ i ].v2 ] ); faces.push_back( vertex_indices[ out->faces[ i ].v3 ] ); } std::get< 2 >( glyphs.back() ) = faces.size() - std::get< 1 >( glyphs.back() ); ttf_free_mesh( out ); } } } } ௖఺ΠϯσοΫεΛ௥Ճ͢Δ ௖఺ΠϯσοΫεͷ͔͜͜Β ͜ͷ਺ͷ௖఺͕glyph_idͷάϦϑͰ͢

Slide 93

Slide 93 text

nlohmann::json root; root[ "asset" ] = nlohmann::json::object({ { "generator", "ttf_to_gltf" }, { "version", "2.0" } }); root[ "buffers" ] = nlohmann::json::array(); root[ "buffers" ].push_back( nlohmann::json::object({ { "uri", "font.bin" }, { "byteLength", vertices.size() * sizeof( float ) + faces.size() * sizeof( std::uint32_t ) } }) ); root[ "bufferViews" ] = nlohmann::json::array(); for( unsigned int i = 0u; i != glyphs.size(); ++i ) { const auto begin = std::get< 1 >( glyphs[ i ] ); const auto size = std::get< 2 >( glyphs[ i ] ); root[ "bufferViews" ].push_back( nlohmann::json::object({ { "buffer", 0 }, { "target", 34963 }, { "byteOffset", glTFͷϔομ͸ී௨ͷJSONͳͷͰ ී௨ͷJSONΤϯίʔμͰ࡞ΕΔ

Slide 94

Slide 94 text

root[ "bufferViews" ] = nlohmann::json::array(); for( unsigned int i = 0u; i != glyphs.size(); ++i ) { const auto begin = std::get< 1 >( glyphs[ i ] ); const auto size = std::get< 2 >( glyphs[ i ] ); root[ "bufferViews" ].push_back( nlohmann::json::object({ { "buffer", 0 }, { "target", 34963 }, { "byteOffset", vertices.size() * sizeof( float ) + begin * sizeof( std::uint32_t ) }, { "byteLength", size * sizeof( std::uint32_t ) }, }) ); } root[ "bufferViews" ].push_back( nlohmann::json::object({ { "buffer", 0 }, { "target", 34962 }, { "byteLength", vertices.size() * sizeof( float ) }, }) ); root[ "accessors" ] = nlohmann::json::array(); for( unsigned int i = 0u; i != glyphs.size(); ++i ) { const auto begin = std::get< 1 >( glyphs[ i ] ); const auto size = std::get< 2 >( glyphs[ i ] ); ֤άϦϑͷઌ಄Λࢦ͢ όοϑΝϏϡʔΛ࡞Δ ࠷ޙʹ௖఺഑ྻͷ όοϑΝϏϡʔΛ࡞Δ

Slide 95

Slide 95 text

root[ "accessors" ] = nlohmann::json::array(); for( unsigned int i = 0u; i != glyphs.size(); ++i ) { const auto begin = std::get< 1 >( glyphs[ i ] ); const auto size = std::get< 2 >( glyphs[ i ] ); root[ "accessors" ].push_back( nlohmann::json::object({ { "bufferView", i }, { "componentType", 5125 }, // 32bit int { "type", "SCALAR" }, { "count", size } }) ); } root[ "accessors" ].push_back( nlohmann::json::object({ { "bufferView", glyphs.size() }, { "componentType", 5126 }, // 32bit float { "type", "VEC3" }, { "count", vertices.size() / 3u }, { "min", nlohmann::json::array({ min.first, min.second, 0.f })}, { "max", nlohmann::json::array({ max.first, max.second, 0.f })} }) ); ֤όοϑΝϏϡʔΛࢦ͢ ΞΫηαΛ࡞Δ ௖఺഑ྻΛࢦ͢ΞΫηαΛ࡞Δ

Slide 96

Slide 96 text

for( unsigned int i = 0u; i != glyphs.size(); ++i ) { const auto glyph_id = std::get< 0 >( glyphs[ i ] ); root[ "meshes" ].push_back( nlohmann::json::object({ { "primitives", nlohmann::json::array({ nlohmann::json::object({ { "attributes", nlohmann::json::object({ { "POSITION", glyphs.size() } })}, { "indices", i } })})}, { "name", std::to_string( glyph_id ) } }) ); } root[ "nodes" ] = nlohmann::json::array(); for( unsigned int i = 0u; i != glyphs.size(); ++i ) { const auto glyph_id = std::get< 0 >( glyphs[ i ] ); root[ "nodes" ].push_back( nlohmann::json::object({ { "mesh", i }, { "name", std::to_string( glyph_id ) } }) ); } root[ "scene" ] = 0; root[ "scenes" ].push_back( nlohmann::json::object({ { "nodes", nlohmann::json::array() } ͜ͷΞΫηα͔Β ௖఺ΠϯσοΫεΛಡΉ ͜ͷΞΫηα͔Β ௖఺഑ྻΛಡΈ ͦΜͳϝογϡΛ 1ؚͭΉϊʔυ ϊʔυ໊͸glyph_idʹ͓ͯ͘͠

Slide 97

Slide 97 text

{ std::fstream bin( bin_filename, std::ios::out|std::ios::binary ); bin.write( reinterpret_cast< const char* >( vertices.data() ), vertices.size() * sizeof( float ) ); bin.write( reinterpret_cast< const char* >( faces.data() ), faces.size() * sizeof( std::uint32_t ) ); } { if( format == "json" ) { std::fstream json( json_filename, std::ios::out ); json << root.dump( 2 ) << std::endl; } else if( format == "bson" ) { std::fstream json( json_filename, std::ios::out|std::ios::binary ); auto serialized = nlohmann::json::to_bson( root ); json.write( reinterpret_cast< const char* >( serialized.data() ), serialized.size() ); } GPUʹૹΔόΠφϦΛ ϑΝΠϧʹు͘ ϔομͷJSONΛ ϑΝΠϧʹు͘

Slide 98

Slide 98 text

ී௨ͷglTF͔ͩΒ BlenderͰಡΊΔ 1ͭͷάϦϑ͕ 1ͭͷϊʔυʹͳ͍ͬͯΔ ΛϕʔεϥΠϯͱͯ͠ άϦϑ͕ฒΜͰ͍Δ y = 0

Slide 99

Slide 99 text

font command_buffer_recorder_t::load_font( std::filesystem::path path, const std::shared_ptr< allocator_t > &allocator ) { fx::gltf::Document doc = fx::gltf::LoadFromText( path.string() ); if( doc.buffers.size() != 1u ) throw invalid_font(); auto buffer_path = std::filesystem::path( doc.buffers[ 0 ].uri ); if( buffer_path.is_relative() ) buffer_path = path.parent_path() / buffer_path; auto buffer = load_buffer_from_file( allocator, buffer_path.string(), vk::BufferUsageFlagBits::eVertexBuffer|vk::BufferUsageFlagBits::eIndexBuffer ); const auto vertex_buffer_view = std::find_if( doc.bufferViews.begin(), doc.bufferViews.end(), []( const auto &v ) { return v.target == fx::gltf::BufferView::TargetType::ArrayBuffer; } ); if( vertex_buffer_view == doc.bufferViews.end() ) throw invalid_font(); const std::uint32_t vertex_buffer_offset = vertex_buffer_view->byteOffset; const std::uint32_t vertex_buffer_length = vertex_buffer_view->byteLength; glTFΛύʔεͯ͠ όΠφϦΛGPUʹૹΔ

Slide 100

Slide 100 text

if( accessor.type != fx::gltf::Accessor::Type::Scalar ) throw invalid_font(); if( accessor.bufferView >= doc.bufferViews.size() ) throw invalid_font(); const auto &buffer_view = doc.bufferViews[ accessor.bufferView ]; if( buffer_view.buffer != 0u ) throw invalid_font(); if( buffer_view.target != fx::gltf::BufferView::TargetType::ElementArrayBuffer ) throw invalid_font(); const auto offset = buffer_view.byteOffset - vertex_index_offset; constexpr static std::uint32_t face_size = ( sizeof( std::uint32_t ) * 3u ); if( offset % face_size ) throw invalid_font(); if( buffer_view.byteLength % face_size ) throw invalid_font(); hash.insert( std::make_pair( gid, glyph_index{ std::uint32_t( offset / sizeof( std::uint32_t ) ), std::uint32_t( buffer_view.byteLength / sizeof( std::uint32_t ) ) } ) ); } ͋Δglyph_id͕ཁٻ͞Εͨ࣌ʹ ௖఺ΠϯσοΫεͷ Ͳ͔͜ΒͲ͜·ͰΛ࢖͏΂͖͔Λه࿥ͨ͠ unordered_map

Slide 101

Slide 101 text

No content

Slide 102

Slide 102 text

จࣈΛGPUͰେྔʹඳ͖͍ͨ

Slide 103

Slide 103 text

CPU͔Β΋GPU͔Β΋ݟ͑ΔϝϞϦ GPU CPU ௕ํܗ × 500 Πϯελϯγϯά 1ίϚϯυͰಉ͡τϙϩδͷਤܗΛେྔʹඳ͘ ௕ํܗ0ͷ഑ஔ ௕ํܗ1ͷ഑ஔ ௕ํܗ2ͷ഑ஔ ௕ํܗ3ͷ഑ஔ ⋮ ݸʑͷจࣈ͸τϙϩδ͕ҟͳΔҝ ΠϯελϯγϯάͰ·ͱΊͯඳ͚ͳ͍

Slide 104

Slide 104 text

CPU͔Β΋GPU͔Β΋ݟ͑ΔϝϞϦ GPU CPU Indirect Draw 1ίϚϯυͰҟͳΔτϙϩδͷਤܗΛେྔʹඳ͘ άϦϑ0ͷ഑ஔ άϦϑ1ͷ഑ஔ άϦϑ2ͷ഑ஔ άϦϑ3ͷ഑ஔ ⋮ άϦϑ0ͷ௖఺ͷಡΈํ άϦϑ1ͷ௖఺ͷಡΈํ άϦϑ2ͷ௖఺ͷಡΈํ άϦϑ3ͷ௖఺ͷಡΈํ 
 ⋮ ͜͜ʹྻڍͨ͠΍ͭඳ͍ͯ

Slide 105

Slide 105 text

void text_renderer::add_glyph( std::uint32_t glyph_id, float x, float y, float size, const std::array< float, 4u > &color, std::uint16_t depth, std::uint16_t texid, std::uint16_t semid ) { auto glyph_info = font_info.index.find( glyph_id ); if( glyph_info != font_info.index.end() ) { const auto instance_id = instance_count++; uniforms_host.rects[ instance_id ].offset[ 0 ] = x * scale; uniforms_host.rects[ instance_id ].offset[ 1 ] = y * scale; uniforms_host.rects[ instance_id ].extent[ 0 ] = size * scale; uniforms_host.rects[ instance_id ].extent[ 1 ] = size * scale; uniforms_host.rects[ instance_id ].color = glm::vec4( color[ 0 ], color[ 1 ], color[ 2 ], color[ 3 ] ); uniforms_host.rects[ instance_id ].depth = depth; จࣈͷ௥ՃΛཁٻ͞ΕͨΒ ͦͷάϦϑ͕ GPUʹૹͬͨσʔλͷதʹ͋Δ͔Λௐ΂ͯ

Slide 106

Slide 106 text

if( glyph_info != font_info.index.end() ) { const auto instance_id = instance_count++; uniforms_host.rects[ instance_id ].offset[ 0 ] = x * scale; uniforms_host.rects[ instance_id ].offset[ 1 ] = y * scale; uniforms_host.rects[ instance_id ].extent[ 0 ] = size * scale; uniforms_host.rects[ instance_id ].extent[ 1 ] = size * scale; uniforms_host.rects[ instance_id ].color = glm::vec4( color[ 0 ], color[ 1 ], color[ 2 ], color[ 3 ] ); uniforms_host.rects[ instance_id ].depth = depth; uniforms_host.rects[ instance_id ].texid = texid; uniforms_host.rects[ instance_id ].semantic[ 0 ] = semid; uniforms_host.rects[ instance_id ].semantic[ 1 ] = 0; indirect_host[ instance_id ].indexCount = glyph_info->second.vertex_count; indirect_host[ instance_id ].instanceCount = 1u; indirect_host[ instance_id ].firstIndex = glyph_info->second.vertex_offset; indirect_host[ instance_id ].vertexOffset = 0u; indirect_host[ instance_id ].firstInstance = instance_id; } } άϦϑͷ৭ͱ഑ஔ άϦϑͷ௖఺ΛͲͷҐஔ͔ΒಡΉ͔

Slide 107

Slide 107 text

void text_renderer::draw( gct::command_buffer_recorder_t &recorder ) { recorder.bind_pipeline( pipeline ); recorder.bind_descriptor_set( vk::PipelineBindPoint::eGraphics, pipeline_layout, descriptor_set ); recorder.bind_vertex_buffer( font_info.buffer ); recorder.bind_index_buffer( font_info.buffer, font_info.offset, vk::IndexType::eUint32 ); recorder->drawIndexedIndirect( **indirect_device, 0, instance_count, sizeof( VkDrawIndexedIndirectCommand ) ); } ϑΥϯτͷ௖఺഑ྻΛ࢖͏ ϑΥϯτͷ௖఺ΠϯσοΫεΛ࢖͏ ͜͜ʹஔ͍ͯ͋Δ௖఺ͷಡΈํʹैͬͯ ͜ͷ਺ͷάϦϑΛඳը

Slide 108

Slide 108 text

No content

Slide 109

Slide 109 text

จࣈαΠζ෼ͮͭӈʹਐΉ ຊ౰ʹͦΕͰେৎ෉?

Slide 110

Slide 110 text

όΠτྻ ୯७ʹฒ΂Δͱ ਖ਼͍͠දࣔ H e l l o 48 65 6c 6c 6f Hello Hello ӳޠ จࣈαΠζ෼ͮͭӈʹਐΉ

Slide 111

Slide 111 text

όΠτྻ ୯७ʹฒ΂Δͱ ਖ਼͍͠දࣔ ͜ Μ ʹ ͪ ͸ e3 81 93 e3 82 93 e3 81 ab e3 81 a1 e3 81 af ͜Μʹͪ͸ ͜Μʹͪ͸ ೔ຊޠ จࣈαΠζ෼ͮͭӈʹਐΉ

Slide 112

Slide 112 text

όΠτྻ ୯७ʹฒ΂Δͱ ਖ਼͍͠දࣔ ส ว ั ส ด ี e0 b8 aa e0 b8 a7 e0 b8 b1 e0 b8 aa e0 b8 94 e0 b8 b5 ส วั ส ดี ส วั ส ดี ্ʹ৐͔ͬͬͯΔ ด ส ว ส ั ี λΠޠ ෳ਺ͷίʔυϙΠϯτͷฒͼͰάϦϑΛඳ͘΂͖Ґஔ͕มΘΔ

Slide 113

Slide 113 text

όΠτྻ ୯७ʹฒ΂Δͱ ਖ਼͍͠දࣔ न म स ् त े e0 a4 a8 e0 a4 ae e0 a4 b8 e0 a5 8d e0 a4 a4 e0 a5 87 नम स्त े नमस ् त े नम स्ते ࣍ͷίʔυϙΠϯτͱ߹ମͯ͠ܗ͕มΘ͍ͬͯΔ ώϯσΟʔޠ ෳ਺ͷίʔυϙΠϯτͷฒͼͰඳ͘΂͖άϦϑ͕มΘΔ

Slide 114

Slide 114 text

όΠτྻ ୯७ʹฒ΂Δͱ ਖ਼͍͠දࣔ ש ל ו ם d7 a9 d7 9c d7 95 d7 9d םולש שלום םולש ӈ͔Βࠨ ϔϒϥΠޠ 1จࣈඳ͍ͨΒࠨʹਐΉ

Slide 115

Slide 115 text

όΠτྻ ୯७ʹฒ΂Δͱ ਖ਼͍͠දࣔ م ر ح ب ً ط d9 85 d8 b1 d8 ad d8 a8 d9 8b d8 a7 ﺎًﺑﺣرﻣ مرحبً ط ﺎًﺑﺣرﻣ ӈ͔Βࠨ͔ͭ࣍ͷίʔυϙΠϯτͱ߹ମͯ͠ผͷάϦϑʹมԽ ΞϥϏΞޠ

Slide 116

Slide 116 text

HarfBuzz Φʔϓϯιʔεͳ ςΩετγΣΠϐϯάϥΠϒϥϦ ༩͑ΒΕͨจࣈྻ͔Β ϑΥϯτʹ͋ΔͲͷάϦϑΛ ͲͷҐஔʹ ඳ͘΂͖͔ΛٻΊΔ https://harfbuzz.github.io/

Slide 117

Slide 117 text

ส วั ส ดี HarfBuzz͕΍ͬͯ͘ΕΔࣄ ࣍ͷจࣈΛ ඳ͘΂͖ҐஔΛٻΊΔ नम स्ते स ͲͷάϦϑͰ ඳ͘΂͖͔ΛٻΊΔ ࠓ͙͢μ΢ϯϩʔ υ HarfBuzz͕΍ͬͯ͘Εͳ͍ࣄ ௕͍จࣈྻͷંΓฦ͠ םולש שלום จࣈྻͷਐߦํ޲ͷ൑அ ? ? จࣈͷϨϯμϦϯά םולש ৗʹࠨ͔Β ॲཧͰ͖ΔΑ͏ʹฒ΂ସ͑

Slide 118

Slide 118 text

ส วั ส ดี HarfBuzz͕΍ͬͯ͘ΕΔࣄ ࣍ͷจࣈΛ ඳ͘΂͖ҐஔΛٻΊΔ नम स्ते स ͲͷάϦϑͰ ඳ͘΂͖͔ΛٻΊΔ ࠓ͙͢μ΢ϯϩʔ υ HarfBuzz͕΍ͬͯ͘Εͳ͍ࣄ ௕͍จࣈྻͷંΓฦ͠ םולש שלום จࣈྻͷਐߦํ޲ͷ൑அ ? ? จࣈͷϨϯμϦϯά םולש ৗʹࠨ͔Β ॲཧͰ͖ΔΑ͏ʹฒ΂ସ͑ ࠨ͔Βӈʹॻ͘ݴޠͳͷ͔ ӈ͔Βࠨʹॻ͘ݴޠͳͷ͔͸ ΞϓϦέʔγϣϯ͕൑அ HarfBuzz͸ࢦఆ͞Εͨ޲͖ʹจࣈΛฒ΂Δॲཧ͚ͩΛ͢Δ

Slide 119

Slide 119 text

https://unicode.org/reports/tr9/ Unicode Standard Annex #9 Unicode૒ํ޲ΞϧΰϦζϜ ӈ͔ΒࠨʹਐΉݴޠͷจࣈ͕ ؚ·Ε͍ͯΔ৔߹ͷ จࣈͷ഑ஔํ๏Λఆٛ͢Δ ΊΜͲ͍͘͞ϧʔϧ͕ ௕ʑͱॻ͔Ε͍ͯΔ

Slide 120

Slide 120 text

ICU Unicodeʹ·ͭΘΔ ΊΜͲ͍͘͞ॲཧΛ࣮૷ͨ͠ ϥΠϒϥϦ https://icu.unicode.org/

Slide 121

Slide 121 text

U_CAPI UBiDiDirection U_EXPORT2 ubidi_getBaseDirection(const UChar *text, int32_t length ); unicode/ubidi.h ͜ͷจࣈྻͬͯͲͬͪ޲͖? UBiDiDirection::UBIDI_LTR ࠨ͔ΒӈͷςΩετͰ࢝·Δ UBiDiDirection::UBIDI_RTL ӈ͔ΒࠨͷςΩετͰ࢝·Δ UBiDiDirection::NEUTRAL จࣈྻۭ΍Μ… ฦΓ஋

Slide 122

Slide 122 text

An apple is called חופת in Hebrew. .תילגנאב תארקנ חופת apple ࠨ͔ΒӈͷςΩετͷதʹӈ͔ΒࠨͷςΩετ͕͍ࠞͬͯ͟Δ ӈ͔ΒࠨͷςΩετͷதʹࠨ͔ΒӈͷςΩετ͕͍ࠞͬͯ͟Δ ӈ͔Βࠨʹॻ͘ݴޠͰ΋௨ৗ਺ࣈ͸ࠨ͔Βӈʹॻ͘ͷͰ ӈ͔ΒࠨͷςΩετʹ͸೔ৗతʹࠨ͔ΒӈͷςΩετ͕ࠞ͟Δ

Slide 123

Slide 123 text

auto bidi = ubidi_open(); if( !bidi ) std::abort(); ubidi_setPara( bidi, utf16, utf16_length, base_direction == UBIDI_RTL, nullptr, &error ); if( U_FAILURE( error ) ) std::abort(); const auto run_count = ubidi_countRuns( bidi, &error ); for( unsigned int i = 0u; i != run_count; ++i ) { int32_t start = 0u; int32_t length = 0u; auto bidi_dir = ubidi_getVisualRun( bidi, i, &start, &length ); if( bidi_dir == UBIDI_NEUTRAL ) { std::abort(); } if( bidi_dir == UBIDI_MIXED ) { std::abort(); } ICUͰ ਐߦํ޲͕ಉ͡ൣғͰจࣈྻΛ۠੾Δ ൣғͷ਺Λऔಘ ͜ͷൣғ͸Ͳͬͪ޲͖?

Slide 124

Slide 124 text

ส วั ส ดี HarfBuzz͕΍ͬͯ͘ΕΔࣄ ࣍ͷจࣈΛ ඳ͘΂͖ҐஔΛٻΊΔ नम स्ते स ͲͷάϦϑͰ ඳ͘΂͖͔ΛٻΊΔ ࠓ͙͢μ΢ϯϩʔ υ HarfBuzz͕΍ͬͯ͘Εͳ͍ࣄ ௕͍จࣈྻͷંΓฦ͠ םולש שלום จࣈྻͷਐߦํ޲ͷ൑அ ? ? จࣈͷϨϯμϦϯά םולש ৗʹࠨ͔Β ॲཧͰ͖ΔΑ͏ʹฒ΂ସ͑ ௕͍ςΩετ͸ંΓฦͯ͠දࣔ͠ͳ͚Ε͹ͳΒͳ͍ Unicodeจࣈྻʹ͸ંΓฦͯ͠͸͍͚ͳ͍Օॴ͕͋Δ

Slide 125

Slide 125 text

English string should not break in the middle of a word. ೔ຊޠͷจࣈྻͰ͸ࣺͯԾ໊͸ߦ಄ʹ࣋ͬ ͯ͘Δ΂͖Ͱ͸ͳ͍ ͜͜ͳΒંΓฦͯ͠Α͍ ͜͜ͰંΓฦͯ͠͸͍͚ͳ͍ ͜͜ͳΒંΓฦͯ͠Α͍ ͜͜ͰંΓฦͯ͠͸͍͚ͳ͍ ส วั ส ดี 1จࣈͱݟ၏͞ΕΔγʔέϯεͷ్தͰંΓฦ͢΂͖Ͱ͸ͳ͍

Slide 126

Slide 126 text

https://unicode.org/reports/tr14/ Unicode Standard Annex #14 Unicodeߦ෼ׂΞϧΰϦζϜ Unicodeʹؚ·ΕΔੈքதͷݴޠͷ ʮͲͷจࣈͱͲͷจࣈͷؒͳΒ վߦΛڬΜͰ΋ྑ͍Ͱ͔͢?ʯ Λ·ͱΊͨ෺ ΊΜͲ͍͘͞ϧʔϧ͕ ௕ʑͱॻ͔Ε͍ͯΔ

Slide 127

Slide 127 text

auto iter = ubrk_open( UBRK_LINE, locale, utf16nfc + start, length, &error ); para.push_back( run{} ); para.back().is_rtl = is_rtl; std::array< UChar32, 512u > utf32 = { 0 }; int32_t cur = 0u; int32_t next; while( ( next = ubrk_next( iter ) ) != UBRK_DONE ) { std::int32_t utf32_length = 0u; u_strToUTF32( utf32.data(), utf32.size(), &utf32_length, utf16nfc + start + cur, next - cur, &error ); if( U_FAILURE( error ) ) std::abort(); if( utf32_length != 0u ) { auto script_code = uscript_getScript( utf32[ 0 ], &error ); bool newline = is_newline( utf32[ 0 ] ); if( U_FAILURE( error ) ) std::abort(); ubrkΛ࢖͏ͱUnicodeจࣈྻΛ ʮվߦΛڬΜͰ͸͍͚ͳ͍ʯ୯ҐͰ۠੾Δࣄ͕Ͱ͖Δ

Slide 128

Slide 128 text

ICU ubidi ICU ubrk HarfBuzz จࣈྻ LTRจࣈྻ RTLจࣈྻ LTRจࣈྻ LTRจࣈྻ RTLจࣈྻ LTRจࣈྻ ୯ޠ ୯ޠ ୯ޠ ୯ޠ ୯ޠ ୯ޠ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ͜͜ͰંΓฦͯ͠େৎ෉ϚʔΫ

Slide 129

Slide 129 text

ICU ubrk HarfBuzz LTRจࣈྻ RTLจࣈྻ LTRจࣈྻ ୯ޠ ୯ޠ ୯ޠ ୯ޠ ୯ޠ ୯ޠ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ࣈ ߦͷંΓฦ͠ ը໘্Ͱͷจࣈͷ഑ஔ

Slide 130

Slide 130 text

1em HarfbuzzͰ͸௕͞͸ Λ1ͱ͢Δ୯ҐͰ දݱ͞ΕΔ 1 1024 em

Slide 131

Slide 131 text

typedef struct hb_glyph_position_t { hb_position_t x_advance; hb_position_t y_advance; hb_position_t x_offset; hb_position_t y_offset; /*< private >*/ hb_var_int_t var; } hb_glyph_position_t; A B x_offset x_advance ΧʔιϧͷҐஔ͔Β ͲΕ͚ͩͣΕͨ৔ॴʹ จࣈΛඳ͘΂͖͔ จࣈΛඳ͍ͨޙͰ ΧʔιϧΛͲΕ͚ͩ ਐΊΔ΂͖͔

Slide 132

Slide 132 text

1pt = 1 72 in ≃ 0.3528mm 1pt = 0.3514mm ݩʑͷఆٛ JISن֨Ͱͷఆٛ จࣈͷେ͖͞ͷ୯Ґ ϙΠϯτ(pt) ͲͪΒʹͤΑݴ͑Δ͜ͱ ը໘ͷ෺ཧతͳେ͖͞ͷ৘ใ͕ඞཁ

Slide 133

Slide 133 text

VESA ENHANCED EXTENDED DISPLAY IDENTIFICATION DATA STANDARD (Defines EDID Structure Version 1, Revision 4) 91ϖʔδΑΓ EDID 1.4ʹ͸1cm୯Ґͷ ը໘ͷେ͖͕͞ ؚ·Ε͍ͯΔ VESA DisplayID Standard Version 2.1 47ϖʔδΑΓ DisplayIDʹ͸ 1mm·ͨ͸0.1mm୯Ґͷ ը໘ͷେؚ͖͕͞·Ε͍ͯΔ σΟεϓϨΠ͸ࣗ਎ͷ෺ཧతͳେ͖͞Λ஻͍ͬͯΔ ϓϩδΣΫλ౳αΠζΛఆٛͰ͖ͳ͍ػثͰ͸ ஻͍ͬͯͳ͍ࣄ΋͋Δ

Slide 134

Slide 134 text

typedef struct VkDisplayPropertiesKHR { VkDisplayKHR display; const char* displayName; VkExtent2D physicalDimensions; VkExtent2D physicalResolution; VkSurfaceTransformFlagsKHR supportedTransforms; VkBool32 planeReorderPossible; VkBool32 persistentContent; } VkDisplayPropertiesKHR; VulkanͰσΟεϓϨΠͷ෺ཧతͳେ͖͞ΛऔΕΔ (mm୯Ґ) औΕͳ͍࣌͸ͱΓ͋͑ͣ96dpiͩͱࢥ͏ Windows compatible͙͠͞Λ͓ͯ͜͠͏

Slide 135

Slide 135 text

จষ͸Wikipediaͷ՘ࢠͷهࣄ͔ΒҾ༻ https://en.wikipedia.org/wiki/Eggplant

Slide 136

Slide 136 text

No content

Slide 137

Slide 137 text

࢖͍ͬͯΔϑΥϯτ(NotoSansThai-Regular)ʹ͸਺ࣈ౳͸ؚ·Ε͍ͯͳ͍ ผͷϑΥϯτʹϑΥʔϧόοΫ͢Δ࢓૊ΈΛ༻ҙ͍ͯ͠ͳ͍ҝදࣔͰ͖ͳ͍

Slide 138

Slide 138 text

άϦϑͷ഑ஔࣗମ͸Chromeͱಉ͡ʹͳ͍ͬͯΔͷͰେৎ෉ͦ͏

Slide 139

Slide 139 text

λΠޠ͸ஈམͷ࠷ॳʹ େ͖ͳࣈԼ͛ΛೖΕΔ͕ ࣈԼ͛Λ࣮૷͍ͯ͠ͳ͍ͷͰ ࠨ୺͔Βจࣈ͕ฒΜͰ͍Δ

Slide 140

Slide 140 text

No content

Slide 141

Slide 141 text

ਐߦํ޲͕ࠞࡏ͢ΔςΩετΛਖ਼͍͠ฒͼͰॻ͚͍ͯΔ ՘ࢠ͸ϔϒϥΠޠͰליצח

Slide 142

Slide 142 text

d7 97 d7 a6 d7 99 d7 9c 20 28 d7 a9 d7 9d 20 d7 9e d7 93 d7 a2 d7 99 3a ל ח צ י ۭന ( ͜ͷׅހ͸ASCIIίʔυͷׅހͰ ࠨ͔Βӈʹॻ͘ςΩετʹ͓͍ͯ͸ӈΛ޲͍͍ͯΔ͕ ӈ͔Βࠨʹॻ͘ςΩετͰ͋Δͱ͍͏ࢦ͕ࣔͳ͞Ε͍ͯΔҝ HarfBuzz͸UAX #9 §3.4 L4ʹैͬͯάϦϑΛ)ʹஔ͖׵͑Δ

Slide 143

Slide 143 text

࢖͍ͬͯΔϑΥϯτ(NotoSansArabic-Regular)ʹ͸Latinܥͷจࣈ͸ؚ·Ε͍ͯͳ͍ ผͷϑΥϯτʹϑΥʔϧόοΫ͢Δ࢓૊ΈΛ༻ҙ͍ͯ͠ͳ͍ҝදࣔͰ͖ͳ͍

Slide 144

Slide 144 text

ͳΜ͔ҧ͏ؾ͕͢Δ͚ͲɺΞϥϏΞޠ͕ಡΊͳ͗ͯ͢͞Α͘෼͔ΒΜ

Slide 145

Slide 145 text

தࠃޠͷจࣈ͸߹ମมܗͨ͠Γ͠ͳ͍ͷͰදࣔࣗମ͸೉͘͠ͳ͍

Slide 146

Slide 146 text

struct GLBHeader { uint32_t magic{}; uint32_t version{}; uint32_t length{}; ChunkHeader jsonHeader{}; }; constexpr uint32_t DefaultMaxBufferCount = 8; constexpr uint32_t DefaultMaxMemoryAllocation = 32 * 4 * 1024 * 1024; constexpr std::size_t HeaderSize{ sizeof(GLBHeader) }; constexpr std::size_t ChunkHeaderSize{ sizeof(ChunkHeader) }; constexpr uint32_t GLBHeaderMagic = 0x46546c67u; constexpr uint32_t GLBChunkJSON = 0x4e4f534au; constexpr uint32_t GLBChunkBIN = 0x004e4942u; constexpr char const * const MimetypeApplicationOctet = "data:application/octet-stre constexpr char const * const MimetypeGLTFBuffer = "data:application/gltf-buffer;base constexpr char const * const MimetypeImagePNG = "data:image/png;base64"; constexpr char const * const MimetypeImageJPG = "data:image/jpeg;base64"; fx/gltf.h 43985ϊʔυΛؚΉڊେͳglTFΛ glTFύʔαͷfx-gltf͕ҟৗͳglTFͱ൑அ͢Δ όοϑΝͷ࠷େαΠζΛ4ഒʹ͢ΔͱಡΊΔ

Slide 147

Slide 147 text

No content

Slide 148

Slide 148 text

GUI දࣔ ೖྗ = +

Slide 149

Slide 149 text

Ϣʔβۭؒ Ϣʔβۭؒ ΞϓϦέʔγϣϯ xcb αʔό ͓લɺΫϦοΫ͞ΕͯΔͧ Xαʔό͕ډΔ৔߹ ೖྗΠϕϯτΛXαʔό͕௨஌ͯ͘͠Δ

Slide 150

Slide 150 text

Ϣʔβۭؒ Ϣʔβۭؒ Χʔωϧۭؒ Linux evdev libinput Ϛ΢ε͕ಈ͖·ͨ͠ ΞϓϦέʔγϣϯ xcb αʔό ͓લɺΫϦοΫ͞ΕͯΔͧ Xαʔό͸࠷΋ԼͷϨΠϠʔͰ͸ͳ͍ HIDυϥΠό Ϛ΢εͷࠨϘλϯ͕ԡ͞Ε·ͨ͠

Slide 151

Slide 151 text

Ϣʔβۭؒ Χʔωϧۭؒ Linux evdev libinput ΞϓϦέʔγϣϯ ͜͏͢Ε͹ Xαʔό͕ແͯ͘΋ ೖྗΠϕϯτΛऔΕΔ HIDυϥΠό Ϛ΢ε͕ಈ͖·ͨ͠ Ϛ΢εͷࠨϘλϯ͕ԡ͞Ε·ͨ͠

Slide 152

Slide 152 text

void libinput_t::libinput_internal_t::poll() { auto udev = udev_new(); libinput_interface interface; interface.open_restricted = open_restricted; interface.close_restricted = close_restricted; auto li = libinput_udev_create_context(&interface, nullptr, udev); if( li == nullptr ) { std::abort(); } if( libinput_udev_assign_seat(li, "seat0") != 0 ) { std::abort(); } auto libinput_fd = libinput_get_fd( li ); while( 1 ) { int e = 0u; if( ( e = libinput_dispatch( li ) ) != 0 ) { throw std::system_error( std::make_error_code( std::errc( -e ) ), "libinput_t::poll : initial libinput_dispatch failed." ); } libinput_event *raw_event = nullptr; while ((raw_event = libinput_get_event( li )) != nullptr) { std::unique_ptr< libinput_event, libinput_event_deleter > event( raw_event ); const auto type = libinput_event_get_type( raw_event ); if( type == LIBINPUT_EVENT_DEVICE_ADDED ) { udevΛ։͘ libinputͷίϯςΩετΛ࡞Δ γʔτΛ࡞Δ Πϕϯτ͋ͬͨΒ͘Ε

Slide 153

Slide 153 text

ԿΒ͔ͷೖྗΠϕϯτ͕ى͜Δͱ ͜ͷfdʹ௨஌͕͘ΔͷͰ epollͰ଴ͭ if( ( e = libinput_dispatch( li ) ) != 0 ) { throw std::system_error( std::make_error_code( std::errc( -e ) ), "libinput_t::poll : initial libinput_dispatch failed." ); } } try { auto event = sched::wait( epoll_notifier->epoll( EPOLLIN, libinput_fd ) | epoll_notifier->epoll( EPOLLIN, set_fd ) ); if( event.data.fd == libinput_fd ) { } else if( event.data.fd == set_fd ) { std::uint64_t temp; if( read( set_fd, &temp, sizeof( temp ) ) < 0 ) { throw std::system_error( std::make_error_code( std::errc( errno ) ), "libinput_t::call : broken event notifier." ); } if( !end ) { } else {

Slide 154

Slide 154 text

thread_pool->add_co( [ thread_pool=thread_pool, pointer=pointer, &cursor_x, &cursor_y, &cursor_moved ]() { while( 1 ) { for( auto e: gct::sched::wait( pointer->get_future() ) ) { if( e.event.index() == 0 ) { auto &m = std::get< gct::input::pointer_moved >( e.event ); cursor_moved = true; cursor_x += m.dx; cursor_y += m.dy; } } } } ); Ϛ΢ε͕ಈ͍ͨΠϕϯτΛरͬͯ

Slide 155

Slide 155 text

if( fb.initial || cursor_moved ) { { auto recorder = sync.command_buffer->begin(); if( cursor_moved ) { cursor_moved = false; window.reset(); window.add_rectangle( vk::Rect2D{ vk::Offset2D{ cursor_x, height-cursor_y }, vk::Extent2D{ 64u, 64u } }, gct::srgb_oetf( gct::html_color( 0xFFFFFF ) ), 1u, true, 0u, 0u, 0u ); for( auto &f: framebuffers ) { f.initial = true; } } window( recorder ); recorder.blit( window.get_color(), fb.color ); Χʔιϧ͕ಈ͍͍ͯͨΒ ৽͍͠ҐஔʹΧʔιϧΛ࠶ඳը

Slide 156

Slide 156 text

No content

Slide 157

Slide 157 text

thread_pool->add_co( [thread_pool=thread_pool,keyboard=keyboard]() { while( 1 ) { for( auto c: wait( keyboard->get_future() ) ) { std::cout << c.code; if( c.state == gct::input::key_state::released ) std::cout << " released" << std::endl; else std::cout << " pressed" << std::endl; } } } ); ΩʔϘʔυͷΠϕϯτΛरͬͯ த਎Λදࣔ

Slide 158

Slide 158 text

$ ./src/example/libinput_keycode/libinput_keycode 36 pressed 36 released 37 pressed 37 released 38 pressed 38 released 39 pressed 39 released 39 pressed 39 released 39 pressed 38 pressed 39 released 38 released 53 pressed 52 pressed 52 released 50 pressed 51 pressed 50 released ͜ͷ൪߸͸Կ?

Slide 159

Slide 159 text

#define KEY_Q 16 #define KEY_W 17 #define KEY_E 18 #define KEY_R 19 #define KEY_T 20 #define KEY_Y 21 #define KEY_U 22 #define KEY_I 23 #define KEY_O 24 #define KEY_P 25 #define KEY_LEFTBRACE 26 #define KEY_RIGHTBRACE 27 #define KEY_ENTER 28 #define KEY_LEFTCTRL 29 #define KEY_A 30 #define KEY_S 31 #define KEY_D 32 #define KEY_F 33 #define KEY_G 34 #define KEY_H 35 #define KEY_J 36 /usr/include/linux/input-event-codes.h LinuxͷೖྗΠϕϯτͷ൪߸

Slide 160

Slide 160 text

#define KEY_Q 16 #define KEY_W 17 #define KEY_E 18 #define KEY_R 19 #define KEY_T 20 #define KEY_Y 21 #define KEY_U 22 #define KEY_I 23 #define KEY_O 24 #define KEY_P 25 #define KEY_LEFTBRACE 26 #define KEY_RIGHTBRACE 27 #define KEY_ENTER 28 #define KEY_LEFTCTRL 29 #define KEY_A 30 #define KEY_S 31 #define KEY_D 32 #define KEY_F 33 #define KEY_G 34 #define KEY_H 35 #define KEY_J 36 /usr/include/linux/input-event-codes.h Πϕϯτ KEY_A ͕ى͖ͨΒ ΩʔϘʔυͷA͕ԡ͞Εͨͱ͍͏ҙຯ ͱ͸ݶΒͳ͍

Slide 161

Slide 161 text

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 56 57 58 100 97 139 125 126 KEY_A(30) ANSIΩʔϘʔυ(US഑ྻ)ͷA͕͋ΔҐஔͷ Ωʔ͕ԡ͞Εͨͱ͍͏ҙຯ

Slide 162

Slide 162 text

ANSI ISO ΩϦϧจࣈܥ ؖࠃ2Ϙϧࣜ JIS KEY_A(30) A͔Ͳ͏͔͸஌ΒΜ͕ ͜ͷҐஔͷΩʔ͕ԡ͞Εͨͱ͍͏ҙຯ

Slide 163

Slide 163 text

KEY_A(30) 1 2 3 4 5 6 7 8 9 0 A Z E R T Y U I O P Q S D F G H J K L M W X C V B N ISOΩʔϘʔυ ϑϥϯεޠ AZERTY഑ྻͷ৔߹ KEY_A͸Q͕ԡ͞Εͨͱ͍͏ҙຯ

Slide 164

Slide 164 text

xkbcommon X Window System͔Β X Keyboard Extension(xkb)ͷ ෦෼͚ͩΛ੾Γग़ͨ͠΋ͷ /usr/share/X11/xkb/ ͋ͨΓʹస͕͍ͬͯΔ ม׵දΛ࢖ͬͯ ͲͷҐஔͷΩʔ͕ԡ͞Ε͔ͨΛ ԿͷจࣈͷΩʔ͕ೖྗ͞Ε͔ͨʹ ม׵͢Δ https://xkbcommon.org/

Slide 165

Slide 165 text

libinput͸ʮͲͷҐஔͷΩʔ͕ԡ͞Ε͔ͨʯΛΑͯ͘͜͠Δ xkbcommon͸ΩʔϘʔυϨΠΞ΢τΛࢦఆ͢Δͱ ʮͲͷҐஔͷΩʔ͕ԡ͞Ε͔ͨʯΛ ʮԿͷจࣈ͕ೖྗ͞Ε͔ͨʯʹม׵͢Δ ΩʔϘʔυϨΠΞ΢τͷ৘ใ͕ඞཁ

Slide 166

Slide 166 text

$ localectl System Locale: LANG=ja_JP.utf8 VC Keymap: jp106 X11 Layout: jp X11 Model: jp106 X11 Variant: OADG109A X11 Options: terminate:ctrl_alt_bksp ΩʔϘʔυϨΠΞ΢τͷ৘ใ ͜ΕΞϓϦέʔγϣϯ͔ΒͲ͏΍ͬͯऔΔͷ?

Slide 167

Slide 167 text

dbus όΠφϦܗࣜͷ γϦΞϥΠθʔγϣϯϑΥʔϚοτ ٴͼͦΕΛ࢖ͬͨ ϓϩηεؒ௨৴ͷن֨ https://www.freedesktop.org/wiki/Software/dbus/

Slide 168

Slide 168 text

auto dbus_locale = sdbus::createProxy( "org.freedesktop.locale1", "/org/freedesktop/locale1" ); auto [layout,model,variant,options] = wait( gct::dbus::call< sdbus::Variant >( dbus_locale->callMethodAsync( "Get" ) .onInterface( "org.freedesktop.DBus.Properties" ) .withArguments( "org.freedesktop.locale1", "X11Layout" ) ) & gct::dbus::call< sdbus::Variant >( dbus_locale->callMethodAsync( "Get" ) .onInterface( "org.freedesktop.DBus.Properties" ) .withArguments( "org.freedesktop.locale1", "X11Model" ) ) & gct::dbus::call< sdbus::Variant >( dbus_locale->callMethodAsync( "Get" ) .onInterface( "org.freedesktop.DBus.Properties" ) .withArguments( "org.freedesktop.locale1", "X11Variant" ) ) & gct::dbus::call< sdbus::Variant >( dbus_locale->callMethodAsync( "Get" ) .onInterface( "org.freedesktop.DBus.Properties" ) .withArguments( "org.freedesktop.locale1", "X11Options" ) ) ); γεςϜόεͷ org.freedesktop.locale1ͷ /org/freedesktop/locale1ʹܨ͍Ͱ ϓϩύςΟΛर͏ͱऔΕΔ

Slide 169

Slide 169 text

auto raw_ctx = xkb_context_new( XKB_CONTEXT_NO_FLAGS ); if( !raw_ctx ) { throw std::system_error( std::make_error_code( std::errc::not_supported ), "xkbcommon_t::xkbcommon_t : xkb_context_new failed." ); } ctx.reset( raw_ctx ); auto raw_keymap = xkb_keymap_new_from_names( ctx.get(), &names, XKB_KEYMAP_COMPILE_NO_FLAGS ); if( !raw_keymap ) { throw std::system_error( std::make_error_code( std::errc::not_supported ), "xkbcommon_t::xkbcommon_t : xkb_keymap_new_from_names failed." ); } keymap.reset( raw_keymap ); auto raw_state = xkb_state_new( keymap.get() ); if( !raw_state ) { throw std::system_error( std::make_error_code( std::errc::not_supported ), "xkbcommon_t::xkbcommon_t : xkb_state_new failed." ); } state.reset( raw_state ); xkbͷίϯςΩετΛ࡞Δ ΩʔϘʔυϨΠΞ΢τͷ໊લ͔Β ΩʔϚοϓΛݟ͚ͭΔ ΩʔϘʔυͷ ঢ়ଶϚγϯΛ࡞Δ

Slide 170

Slide 170 text

std::shared_ptr< gct::input::input_buffer< gct::input::libinput_event_category::keyboard_event, gct::input::xkb_key_event > > keyboard( new gct::input::input_buffer< gct::input::libinput_event_category::keyboard_event, gct::input::xkb_key_event >( libinput, []( auto &dest, auto *event ) { const auto key = libinput_event_keyboard_get_key( event ); const auto time = std::chrono::microseconds( libinput_event_keyboard_get_time_usec( event ) ); const auto state = gct::input::libinput_key_state_to_gct_key_state( libinput_event_keyboard_get_key_state( event ) ); dest.push_back( gct::input::xkb_key_event{ 0u, key + 8u, state, time } ); } ) ); xkbͷΩʔϘʔυΠϕϯτͷ൪߸͸ LinuxͷΩʔϘʔυΠϕϯτͷ൪߸+8 libinput͔ΒདྷͨΠϕϯτΛ xkbcommonʹ౉͢

Slide 171

Slide 171 text

thread_pool->add_co( [xkb_state=xkb_state,&current_text,&text_changed,&text_guard]() { try { while( 1 ) { for( auto c: wait( xkb_state->get_future() ) ) { if( c.state == gct::input::key_state::pressed ) { if( 0x20 <= c.sym && c.sym <= 0x7F ) { std::scoped_lock< std::mutex > lock( text_guard ); current_text += char( c.sym ); std::cout << current_text << std::endl; text_changed = true; } else if( c.sym == 0xFF08 ) { if( !current_text.empty() ) { std::scoped_lock< std::mutex > lock( text_guard ); current_text.pop_back(); std::cout << current_text << std::endl; text_changed = true; } } else if( c.sym == 0xFF0d ) { std::scoped_lock< std::mutex > lock( text_guard ); current_text += '\n'; std::cout << current_text << std::endl; text_changed = true; } xkbcommon͔Β ೖྗ͞ΕͨจࣈΛ΋Β͏

Slide 172

Slide 172 text

$ ./src/example/libinput_keycode/libinput_keysym H He Hel Hell Hello Hello, Hello, Hello, W Hello, Wo Hello, Wor Hello, Worl Hello, World Hello, World! Hello, World!a Hello, World! Hello, World Hello, Worl Hello, Wor Hello, Wo Hello, W ʮԿͷจࣈ͕ೖྗ͞Ε͔ͨʯ ͕औΕΔ

Slide 173

Slide 173 text

No content

Slide 174

Slide 174 text

No content

Slide 175

Slide 175 text

Nihongo ga utenai...

Slide 176

Slide 176 text

Ϣʔβۭؒ Ϣʔβۭؒ Χʔωϧۭؒ Linux evdev libinput ΞϓϦέʔγϣϯ xcb αʔό IMMODULE͕ΩʔϘʔυΠϕϯτΛ ೖྗϝιουʹ఻͑Δ HIDυϥΠό Qt΍GTK+ IMMODULE Ϣʔβۭؒ ೖྗϝιου ม׵Τϯδϯ

Slide 177

Slide 177 text

Ϣʔβۭؒ Χʔωϧۭؒ Linux ͜͏͢Ε͹೔ຊޠΛೖྗͰ͖Δ Ϣʔβۭؒ ೖྗϝιου ม׵Τϯδϯ ΞϓϦέʔγϣϯ evdev libinput HIDυϥΠό

Slide 178

Slide 178 text

IMMODULE UIM SCIM IBus fcitx ௚઀ϦϯΫ socket dbus dbus Anthy Mozc SKK libhangul Chewing

Slide 179

Slide 179 text

ΞϓϦέʔγϣϯ UIM SCIM IBus fcitx dbus Anthy Mozc SKK libhangul Chewing dbusͰ fcitxͱձ࿩͠Α͏

Slide 180

Slide 180 text

fcitx5::fcitx5_internal::fcitx5_internal( const std::shared_ptr< sched::thread_pool_t > &tp ) : thread_pool( tp ) { conn = sdbus::createDefaultBusConnection(); input_method = sdbus::createProxy( *conn, "org.fcitx.Fcitx5", "/org/freedesktop/portal/inputmethod" ); conn->enterEventLoopAsync(); } void fcitx5::fcitx5_internal::run() { thread_pool->add_co( [self=shared_from_this()]() { self->poll(); } ); } void fcitx5::fcitx5_internal::poll() { auto [version] = sched::wait( gct::dbus::call< std::uint32_t >( input_method->callMethodAsync( "Version" ) .onInterface( "org.fcitx.Fcitx.InputMethod1" ) .withArguments() ) ηογϣϯόεͷ org.fcitx5.Fcitx5ͷ /org/freedesktop/portal/inputmethodʹܨ͙

Slide 181

Slide 181 text

); } void fcitx5::fcitx5_internal::poll() { auto [version] = sched::wait( gct::dbus::call< std::uint32_t >( input_method->callMethodAsync( "Version" ) .onInterface( "org.fcitx.Fcitx.InputMethod1" ) .withArguments() ) ); std::cout << "fcitx5 version : " << version << std::endl; std::vector< sdbus::Struct< std::string, std::string > > args{ sdbus::make_struct( std::string( "program" ), std::string( "hoge" ) ), sdbus::make_struct( std::string( "display" ), std::string( "x11:" ) ) }; auto [path,wtf] = sched::wait( gct::dbus::call< sdbus::ObjectPath, std::vector< std::uint8_t > >( input_method->callMethodAsync( "CreateInputContext" ) .onInterface( "org.fcitx.Fcitx.InputMethod1" ) .withArguments( args ) ) ); input_context = sdbus::createProxy( *conn, "org.fcitx.Fcitx5", path ); CreateInputContextͰίϯςΩετΛ࡞Δͱ ίϯςΩετͷύε͕໯͑Δ ίϯςΩετͷύεʹܨ͙

Slide 182

Slide 182 text

thread_pool->add_co( [self=shared_from_this(),e=e,key_state=key_state]() { if( self->input_context ) { auto [result] = sched::wait( gct::dbus::call< bool >( self->input_context->callMethodAsync( "ProcessKeyEvent" ) .onInterface( "org.fcitx.Fcitx.InputContext1" ) .withArguments( std::uint32_t( e.sym ), std::uint32_t( e.code ), std::uint32_t( key_state ), bool( e.state == key_state::released ), std::uint32_t( e.relative_time.count() ) ) ) ); if( !result ) { std::cout << "ProcessKeyEvent failed : " << result << std::endl; } } } xkbcommonʹ௨͢લͷΩʔͷҐஔͱ ௨ͨ͠ޙͷΩʔͷจࣈΛfcitx5ʹૹΔ

Slide 183

Slide 183 text

input_context->uponSignal( "CurrentIM" ) .onInterface( "org.fcitx.Fcitx.InputContext1" ) .call( [self=shared_from_this()]( const std::string &a, const std::string &b, const std::string &c ) { std::optional< promise< std::tuple< std::string, std::string, std::string > > > p; { std::scoped_lock< std::mutex > lock( self->guard ); if( self->current_im_p ) { p = std::move( *self->current_im_p ); self->current_im_p = std::nullopt; } else { self->current_im_v = std::make_tuple( a, b, c ); } } if( p ) { ม׵Τϯδϯ͕੾ΓସΘΔͱ CurrentIMγάφϧͰ ม׵Τϯδϯͷ໊લ͕ඈΜͰ͘Δ

Slide 184

Slide 184 text

input_context->uponSignal( "CommitString" ) .onInterface( "org.fcitx.Fcitx.InputContext1" ) .call( [self=shared_from_this()]( const std::string &s ) { std::optional< promise< std::string > > p; { std::scoped_lock< std::mutex > lock( self->guard ); if( self->commit_p ) { p = std::move( *self->commit_p ); self->commit_p = std::nullopt; } else { self->commit_v += s; } } if( p ) { p->set_value( s ); } } ); input_context->uponSignal( "CurrentIM" ) .onInterface( "org.fcitx.Fcitx.InputContext1" ) .call( [self=shared_from_this()]( ม׵͕֬ఆ͢Δͱ CommitStringγάφϧͰ ֬ఆͨ͠಺༰͕ඈΜͰ͘Δ

Slide 185

Slide 185 text

input_context->uponSignal( "ForwardKey" ) .onInterface( "org.fcitx.Fcitx.InputContext1" ) .call( [self=shared_from_this()]( std::uint32_t a, std::uint32_t b, bool c ) { std::optional< promise< std::vector< std::uint32_t > > > p; { std::scoped_lock< std::mutex > lock( self->guard ); if( self->forward_p ) { p = std::move( *self->forward_p ); self->forward_p = std::nullopt; } else { self->forward_v.push_back( a ); } } if( p ) { p->set_value( std::vector< std::uint32_t >{ a } ); } } ); input_context->uponSignal( "UpdateClientSideUI" ) ม׵Τϯδϯ͕੾ΒΕͨঢ়ଶͰ ೖྗ͞Εͨ಺༰͸ ForwardKeyγάφϧͰ ඈΜͰ͘Δ

Slide 186

Slide 186 text

input_context->uponSignal( "UpdateClientSideUI" ) .onInterface( "org.fcitx.Fcitx.InputContext1" ) .call( [self=shared_from_this()]( const std::vector< sdbus::Struct< std::string, std::int32_t > > &a, std::int32_t b, const std::vector< sdbus::Struct< std::string, std::int32_t > > &c, const std::vector< sdbus::Struct< std::string, std::int32_t > > &d, const std::vector< sdbus::Struct< std::string, std::string > > &e, std::int32_t f, std::int32_t g, bool h, bool i ) { fcitx5_client_ui v; v.message = c.empty() ? std::string() : c[ 0 ].get< 0 >(); v.selected = f; v.page = h; for( auto &x: e ) { v.cands.push_back( x.get< 0 >() ); } std::optional< promise< fcitx5_client_ui > > p; ม׵ީิ΢Οϯυ΢ͷ಺༰Λߋ৽͢΂͖࣌͸ UpdateClientSideUIγάφϧ͕ඈΜͰ͘Δ

Slide 187

Slide 187 text

input_context->uponSignal( "UpdateFormattedPreedit" ) .onInterface( "org.fcitx.Fcitx.InputContext1" ) .call( [self=shared_from_this()]( const std::vector< sdbus::Struct< std::string, std::int32_t > > &a, std::int32_t b ) { fcitx5_preedit v; v.selected = b; for( auto &x: a ) { v.cands.push_back( x.get< 0 >() ); } std::optional< promise< fcitx5_preedit > > p; { std::scoped_lock< std::mutex > lock( self->guard ); if( self->preedit_p ) { p = std::move( *self->preedit_p ); self->preedit_p = std::nullopt; } else { self->preedit_v = v; } Preedit(ະ֬ఆͷจࣈྻ)ͷ಺༰Λมߋ͢΂͖࣌͸ UpdateFormattedPreeditγάφϧ͕ඈΜͰ͘Δ

Slide 188

Slide 188 text

No content

Slide 189

Slide 189 text

ະղܾͷ໰୊

Slide 190

Slide 190 text

͜͏͍͏ͷ ൒ಁ໌ͷ௕ํܗ ޙΖͷཁૉ͕ઌʹඳ͔ΕΔࣄΛ อূ͠ͳ͚Ε͹ͳΒͳ͍ Πϯελϯγϯά͔Β ൒ಁ໌ͷཁૉ͚ͩআ֎ͯ͠ Zιʔτ͠ͳ͚Ε͹ͳΒ͍

Slide 191

Slide 191 text

ॎ ॻ ͖ ɹ ೔ ຊ ޠ ౳ ͷ ͍ ͘ ͭ ͔ ͷ ݴ ޠ Ͱ ͸ ্ ͔ Β Լ ʹ ς Ω ε τ Λ ਐ Ί Δ ॻ ͖ ํ ͕ ఆ ٛ ͞ Ε ͯ ͍ Δ ɹ HarfBuzz ͸ ॎ ॻ ͖ Λ α ϙ τ ͠ ͯ ͍ Δ ͷ Ͱ ೔ ຊ ޠ ͷ จ ࣈ Λ ॎ ॻ ͖ Ͱ ฒ ΂ Δ ࣄ ࣗ ମ ͸ ೉ ͠ ͘ ͳ ͍ ɹ ͠ ͔ ͠ ɹ ॎ ॻ ͖ ͷ ς Ω ε τ ͷ த ʹ English ͷ Α ͏ ͳ ॎ ॻ ͖ Ͱ ͖ ͳ ͍ ݴ ޠ ͕ ࠞ ͟ ͯ ͖ ͨ Β ά Ϧ ϑ Λ ճ స ͞ ͤ ͳ ͚ Ε ͹ ͳ Β ͳ ͍ ɹ ॎ ॻ ͖ ͷ ς Ω ε τ ͷ த ʹ תי ִ רְבִע ʿ Īvrīt ͷ Α ͏ ͳ ӈ ͔ Β ࠨ ʹ ਐ Ή ݴ ޠ ͕ ࠞ ͟ ͯ ͖ ͨ Β Ͳ ͏ ͠ Α ͏

Slide 192

Slide 192 text

ΞϯνΤΠϦΞεΛ͔͚͍ͯͳ͍ͷͰ จࣈ͕݁ߏΨλΨλ͍ͯ͠Δ MSAAΛ࢖͑͹៉ྷʹͳΔ͔΋?

Slide 193

Slide 193 text

OpenType TrueTypeʹ3࣍BézierεϓϥΠϯۂઢͷαϙʔτͳͲ ༷ʑͳػೳ௥ՃΛͨ͠෺ ttf2meshͰ͸ಡΊͳ͍ NotoSansCJK͕OpenTypeͰ ͜Ε͕ಡΊͳ͍ͷ͕݁ߏਏ͍

Slide 194

Slide 194 text

sdbus gct͸MITϥΠηϯεͰ഑෍͍ͯ͠Δ͕ sdbus͕LGPLͳͷͰ gctΛϦϯΫ͢ΔͱʮϦόʔεΤϯδχΞϦϯάͷڐՄʯΛٻΊΒΕΔ sdbus͸ࣗલͰI/OεϨουΛ͍࣋ͬͯΔ͕ Ͱ͖Ε͹gctͷI/OεϨουͰΠϕϯτΛ଴͍ͨͤͨ কདྷతʹdbusΛࣗલͰ࣮૷͢Δ

Slide 195

Slide 195 text

RaspberryPiͰ࣮ߦ͢ΔͱΫϥογϡ͢Δ ଟ෼σεΫϦϓλͷ࢖͍͚͗ͩ͢Ͳ ৄ͘͠͸ௐ΂ΒΕ͍ͯͳ͍

Slide 196

Slide 196 text

·ͱΊ GUI͢Δͷʹ ͸ཁΒͳ͍ ϓϥΠϚϦϊʔυΛѲͬͯ ը໘ͷίϯτϩʔϧΛखʹೖΕΑ͏ libinputͰೖྗΛड͚෇͚Α͏