Upgrade to Pro — share decks privately, control downloads, hide ads and more …

安いハードウェアでVulkan

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for Fadis Fadis
March 20, 2026

 安いハードウェアでVulkan

GPUが高いので、出来るだけ安いハードウェアで3Dグラフィクスに入門する方法を考えます
これは2026年3月20日に行われた Kernel/VM探検隊@つくば No3 での発表動画です
発表動画: https://www.youtube.com/watch?v=dcNCr6WbPRM
ソースコード :https://github.com/Fadis/tiny_vulkan_sample/tree/master
https://github.com/Fadis/generate_simple_vertex_buffer
https://github.com/Fadis/gentoo_on_luckfox_pico_mini

Avatar for Fadis

Fadis

March 20, 2026
Tweet

More Decks by Fadis

Other Decks in Programming

Transcript

  1. ͍҆ϋʔυ΢ΣΞͰ Vulkan NAOMASA MATSUBAYASHI(@fadis_) ࣸਅࡱӨ OK SNS౤ߘ OK ಈը੾Γൈ͖ OK

    https://github.com/Fadis/tiny_vulkan_sample/ https://github.com/Fadis/generate_simple_vertex_buffer/
  2. Luckfox Pico Mini SoC Rockchip RV1103 CPU ARM Cortex-A7 1.2GHz

    x1 ϝϞϦ DDR2 64MB ετϨʔδ MicroSDΧʔυ USB USB 2.0 OTG Ethernet 100Base-TX ͦͷଞ SPIx1/I2Cx1/UARTx3/ADCx2/PWMx6 951ԁ ཪ ද https://www.luckfox.com/Luckfox-Pico/Luckfox-Pico-Mini-A ※2026೥2݄24೔࣌఺
  3. 5.10 5.15 6.1 6.6 6.12 6.18 ຊՈ LTSΧʔωϧ 5.10 6.1

    6.6 rockchip-linux 5.10 luckfox-pico sdk(BSP) LinuxΛRV1103Ͱ ಈ͘Α͏ʹ͢Δ luckfox pico miniͷ DTS౳Λ௥Ճ 2020 2021 2022 2023 2024 2025 Luckfox pico miniͰ LinuxΛಈ͔͢ҝͷมߋ͸ ຊՈͷΧʔωϧʹೖ͍ͬͯͳ͍ มߋ͕ೖ͍ͬͯΔΧʔωϧ͸ ௒ݹ͍
  4. 5.10 5.15 6.1 6.6 6.12 6.18 ຊՈ LTSΧʔωϧ 5.10 6.1

    6.6 rockchip-linux 5.10 luckfox-pico sdk(BSP) LinuxΛRV1103Ͱ ಈ͘Α͏ʹ͢Δ luckfox pico miniͷ DTS౳Λ௥Ճ 2020 2021 2022 2023 2024 2025 ͜͜ͷมߋ͸େͨ͠ྔͰ͸ͳ͍ͷͰ 6.6ͷ্ʹੵΈ௚ͤΔ https://github.com/Fadis/gentoo_on_luckfox_pico_mini/
  5. DDR 306b9977f5 wesley.yao 23/12/21-09:28:37,fwver: v1.15 S5P1 4x fc27 rgef0 rgef1

    DDRConf1 DDR2, BW=16 Col=10 Bk=4 CS0 Row=13 CS=1 Size=64MB 528MHz DDR bin out U-Boot SPL board init U-Boot SPL 2017.09 (Feb 13 2026 - 00:11:13) unknown raw ID 0 0 0 Trying to boot from MMC2 spl: partition error Trying fit image at 0x400 sector ## Verified-boot: 0 ## Checking uboot 0x00200000 (gzip @0x00400000) ... sha256(ff181c7bfb...) + sha256(cc050ec2f4...) + OK ## Checking fdt 0x00257190 ... sha256(f53407e58c...) + OK Total: 314.478/362.685 ms Jumping to U-Boot(0x00200000) U-Boot 2017.09 (Feb 13 2026 - 00:11:13 +0900) Model: Rockchip RV1106 EVB2 Board MPIDR: 0xf00 PreSerial: 2, raw, 0xff4c0000 DRAM: 64 MiB Sysmem: init Relocation Offset: 03d6c000 Relocation fdt: 02df9f78 - 02dfede8 CR: M/C/I DM: v2 no mmc device at slot 1 mmc@ffa90000: 0, mmc@ffaa0000: 1 (SD) Bootdev(atags): mmc 1 MMC1: Legacy, 20Mhz PartType: DOS No misc partition boot mode: None FIT: No boot partition Failed to load DTB, ret=-19 No valid DTB, ret=-22 Failed to get kernel dtb, ret=-22 reading uboot.env Model: Rockchip RV1106 EVB2 Board rockchip_set_serialno: could not find efuse/otp device ## retrieving sd_update.txt ... ** Unable to read file sd_update.txt **
  6. Starting kernel ... [ 0.000000] Booting Linux on physical CPU

    0x0 [ 0.000000] Linux version 6.6.89 (root@cistina) (gcc (Gentoo 15.2.1_p20251122 p4) 15.2.1 20251122, GNU ld (Gentoo 2.4 5.1 p1) 2.45.1) #3 Thu Feb 12 14:51:01 -00 2026 [ 0.000000] CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=10c53c7d [ 0.000000] CPU: div instructions available: patching division code [ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache [ 0.000000] OF: fdt: Machine model: Luckfox Pico Mini [ 0.000000] earlycon: uart8250 at MMIO32 0xff4c0000 (options '') [ 0.000000] printk: bootconsole [uart8250] enabled [ 0.000000] Memory policy: Data cache writeback [ 0.000000] cma: Reserved 1024 KiB at 0x03f00000 [ 0.000000] Zone ranges: [ 0.000000] Normal [mem 0x0000000000000000-0x0000000003ffffff] [ 0.000000] Movable zone start for each node [ 0.000000] Early memory node ranges [ 0.000000] node 0: [mem 0x0000000000000000-0x0000000003ffffff] [ 0.000000] Initmem setup node 0 [mem 0x0000000000000000-0x0000000003ffffff] [ 0.000000] CPU: All CPU(s) started in SVC mode. [ 0.000000] Kernel command line: storagemedia=sd androidboot.storagemedia=sd androidboot.mode=normal rootwait earlyc on=uart8250,mmio32,0xff4c0000 console=ttyFIQ0 root=/dev/mmcblk1p7 snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_p ool=0 androidboot.fwver=uboot-02/13/2026 user_debug=31 earlycon=uart8250,mmio,0xff4c0000,115200n8 console=ttyFIQ0,115200 n8 console=tty0 clk_ignore_unused root=/dev/mmcblk1p3 rootfstype=f2fs rootflags=atgc ro init=/usr/lib/systemd/systemd rk _dma_heap_cma=1M [ 0.000000] Unknown kernel command line parameters "storagemedia=sd user_debug=31", will be passed to user space. [ 0.000000] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes, linear) [ 0.000000] Inode-cache hash table entries: 4096 (order: 2, 16384 bytes, linear) [ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 16240 [ 0.000000] mem auto-init: stack:all(zero), heap alloc:off, heap free:off [ 0.000000] Memory: 56140K/65536K available (5120K kernel code, 214K rwdata, 548K rodata, 1024K init, 155K bss, 8372K reserved, 1024K cma-reserved) [ 0.000000] SLUB: HWalign=64, Order=0-1, MinObjects=0, CPUs=1, Nodes=1 [ 0.000000] NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16 [ 0.000000] rockchip_amp_get_gic_info: get amp gic cpu mask error [ 0.000000] arch_timer: cp15 timer(s) running at 24.00MHz (phys). [ 0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x588fe9dc0, max_idle_ns: 440795202592 ns [ 0.000003] sched_clock: 56 bits at 24MHz, resolution 41ns, wraps every 4398046511097ns [ 0.008796] Switching to timer-based delay loop, resolution 41ns [ 0.015927] Console: colour dummy device 80x30 [ 0.020847] printk: console [tty0] enabled [ 0.025357] printk: bootconsole [uart8250] disabled [ 0.030808] Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=240000) [ 0.030854] CPU: Testing write buffer coherency: ok [ 0.030942] pid_max: default: 4096 minimum: 301 [ 0.031144] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear) [ 0.031194] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear) [ 0.033522] Setting up static identity map for 0x100000 - 0x10003c [ 0.034616] devtmpfs: initialized [ 0.043892] VFP support v0.3: implementor 41 architecture 2 part 30 variant 7 rev 5
  7. .) [ 5.343761] systemd[1]: Starting Journal Service... [ 5.384451] systemd[1]:

    Load Kernel Modules was skipped because no trigger condition checks were met. [ 5.443674] systemd[1]: Starting Remount Root and Kernel File Systems... [ 5.563137] systemd[1]: Starting Apply Kernel Variables... [ 5.681419] systemd[1]: Starting Create Static Device Nodes in /dev gracefully... [ 5.765470] systemd-journald[63]: Collecting audit messages is disabled. [ 5.933713] systemd[1]: Starting Load udev Rules from Credentials... [ 6.124710] systemd[1]: Starting Coldplug All udev Devices... [ 6.416015] systemd[1]: Mounted POSIX Message Queue File System. [ 6.474486] systemd[1]: Started Journal Service. [ 7.392472] systemd-journald[63]: Received client request to flush runtime journal. [ 7.969410] systemd-journald[63]: /var/log/journal/58ded1f0c7ccd83acd0b5f62696c4298/system.journal: Realtime clock ju mped backwards relative to last journal entry, rotating. [ 8.036074] systemd-journald[63]: Rotating system journal. [ 12.172286] platform ffa80000.ethernet: deferred probe pending [ 12.179541] platform ffb00000.usb: deferred probe pending [ 13.276777] rk_gmac-dwmac ffa80000.ethernet: IRQ eth_lpi not found [ 13.284702] rk_gmac-dwmac ffa80000.ethernet: PTP uses main clock [ 13.292259] rk_gmac-dwmac ffa80000.ethernet: supply phy not found, using dummy regulator [ 13.303238] rk_gmac-dwmac ffa80000.ethernet: clock input or output? (input). [ 13.311641] rk_gmac-dwmac ffa80000.ethernet: Can not read property: tx_delay. [ 13.320149] rk_gmac-dwmac ffa80000.ethernet: set tx_delay to 0xffffffff [ 13.328120] rk_gmac-dwmac ffa80000.ethernet: Can not read property: rx_delay. [ 13.336582] rk_gmac-dwmac ffa80000.ethernet: set rx_delay to 0xffffffff [ 13.344639] rk_gmac-dwmac ffa80000.ethernet: integrated PHY? (yes). [ 13.352278] rk_gmac-dwmac ffa80000.ethernet: cannot get clock mac_clk_rx [ 13.360289] rk_gmac-dwmac ffa80000.ethernet: cannot get clock mac_clk_tx [ 13.368377] rk_gmac-dwmac ffa80000.ethernet: cannot get clock clk_mac_speed [ 13.376696] rk_gmac-dwmac ffa80000.ethernet: clock input from PHY [ 13.432915] rk_gmac-dwmac ffa80000.ethernet: init for RMII [ 13.481857] rk_gmac-dwmac ffa80000.ethernet: User ID: 0x30, Synopsys ID: 0x51 [ 13.490462] rk_gmac-dwmac ffa80000.ethernet: DWMAC4/5 [ 13.496994] rk_gmac-dwmac ffa80000.ethernet: DMA HW capability register supported [ 13.506967] rk_gmac-dwmac ffa80000.ethernet: RX Checksum Offload Engine supported [ 13.517016] rk_gmac-dwmac ffa80000.ethernet: TX Checksum insertion supported [ 13.525452] rk_gmac-dwmac ffa80000.ethernet: Wake-Up On Lan supported [ 13.533269] rk_gmac-dwmac ffa80000.ethernet: TSO supported [ 13.540036] rk_gmac-dwmac ffa80000.ethernet: Enable RX Mitigation via HW Watchdog Timer [ 13.550497] rk_gmac-dwmac ffa80000.ethernet: TSO feature enabled [ 13.557813] rk_gmac-dwmac ffa80000.ethernet: Using 40/40 bits DMA host/device width [ 13.764080] rockchip-cpuinfo cpuinfo: SoC : 11031000 [ 13.770550] rockchip-cpuinfo cpuinfo: Serial : 31802f56810ef625 [ 14.162227] Adding 8324092k swap on /dev/mmcblk1p2. Priority:-2 extents:1 across:8324092k SS [ 17.126152] rk_gmac-dwmac ffa80000.ethernet end0: renamed from eth0 [ 19.335775] loadkeys[144]: memfd_create() called without MFD_EXEC or MFD_NOEXEC_SEAL set This is localhost (Linux armv7l 6.6.89) 22:44:25 localhost login: This is localhost (Linux armv7l 6.6.89) 22:44:25 localhost login:
  8. ... // SPI &spi0 { pinctrl-0 = <&spi0m0_clk &spi0m0_miso &spi0m0_mosi

    &spi0m0_cs0>; #address-cells = <1>; #size-cells = <0>; panel: display@0{ compatible = "adafruit,yx240qv29", "ilitek,ili9341"; reg = <0>; spi-max-frequency = <50000000>; dc-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>; reset-gpios = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>; rotation = <90>; status = "okay"; }; }; ... arch/arm/boot/dts/rockchip/rv1103-luckfox-pico-ipc.dtsi ͜͜ʹILI9341ͷӷথ͕͋ΔΑ
  9. Direct Rendering Manager(DRM) root@localhost ~ # ls /dev/dri/ by-path card0

    root@localhost ~ # ls /dev/dri/by-path/ platform-ff500000.spi-cs-0-card ͜ͷσόΠεϑΝΠϧʹioctl͢ΔࣄͰ GPUΛૢ࡞͢ΔཁٻΛΧʔωϧʹ౤͛ΒΕΔ GPU্ͷϝϞϦΛ֬อ͢Δ GPUͰ࣮ߦՄೳόΠφϦΛ࣮ߦ͢Δ σΟεϓϨΠʹૹΔσʔλͷܗࣜΛࢦఆ͢Δ CPU͔Βॻ͚ΔϑϨʔϜόοϑΝΛ࡞Δ ࣮ߦͷಉظɺΩϟογϡͷૢ࡞ Graphics Execution Manager(GEM) Kernel Mode Setting(KMS) etc.
  10. Direct Rendering Manager(DRM) ͋ΔGPU͕Ͳͷૢ࡞Λड͚෇͚Δ͔͸ GPUͷυϥΠόͷ࣮૷࣍ୈ ILI9341ʹ͸ࣗྗͰܭࢉ͢Δػೳ͕ͳ͍ 320x240(ϦϑϨογϡϨʔτෆ໌) ͚͕ͩબ΂Δ DRM༻ޠͰ dumb-buffer

    GPU্ͷϝϞϦΛ֬อ͢Δ GPUͰ࣮ߦՄೳόΠφϦΛ࣮ߦ͢Δ σΟεϓϨΠʹૹΔσʔλͷܗࣜΛࢦఆ͢Δ CPU͔Βॻ͚ΔϑϨʔϜόοϑΝΛ࡞Δ ࣮ߦͷಉظɺΩϟογϡͷૢ࡞
  11. fd = open( devname.c_str(), O_RDWR ); if( fd < 0

    ) { ... } res = drmModeGetResources( fd ); if( res == nullptr ) { ... } creq.width = width; creq.height = height; creq.bpp = bpp; if( drmIoctl( fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq ) ) { ... } std::array< std::uint32_t, 4u > handles{ creq.handle, 0u, 0u, 0u }; std::array< std::uint32_t, 4u > pitches{ creq.pitch, 0u, 0u, 0u }; std::array< std::uint32_t, 4u > offsets{ 0u, 0u, 0u, 0u }; if( drmModeAddFB2( fd, width, height, format, handles.data(), pitches.data(), offsets.data(), &fb, 0u ) ) { ... } for ( int i = 0; i < res->count_connectors; ++i ) { drmModeConnectorPtr candidate = drmModeGetConnectorCurrent( fd, res->connectors[ i ] ); if( !candidate ) continue; for( int j = 0; j < candidate->count_modes; ++j ) { if( candidate->modes[ j ].hdisplay == creq.width && candidate->modes[ j ].vdisplay == creq.height ) { connector = candidate; mode_index = j; i = res->count_connectors; j = candidate->count_modes; } } if( i != res->count_connectors ) drmModeFreeConnector( candidate ); } if( connector == nullptr ) { ... } encoder = drmModeGetEncoder( fd, connector->encoder_id ); if ( encoder == nullptr ) { ... } crtc = drmModeGetCrtc( fd, encoder->crtc_id ); dumb-bufferΛ࡞Δ
  12. std::array< std::uint32_t, 4u > handles{ creq.handle, 0u, 0u, 0u };

    std::array< std::uint32_t, 4u > pitches{ creq.pitch, 0u, 0u, 0u }; std::array< std::uint32_t, 4u > offsets{ 0u, 0u, 0u, 0u }; if( drmModeAddFB2( fd, width, height, format, handles.data(), pitches.data(), offsets.data(), &fb, 0u ) ) { ... } for ( int i = 0; i < res->count_connectors; ++i ) { drmModeConnectorPtr candidate = drmModeGetConnectorCurrent( fd, res->connectors[ i ] ); if( !candidate ) continue; for( int j = 0; j < candidate->count_modes; ++j ) { if( candidate->modes[ j ].hdisplay == creq.width && candidate->modes[ j ].vdisplay == creq.height ) { connector = candidate; mode_index = j; i = res->count_connectors; j = candidate->count_modes; } } if( i != res->count_connectors ) drmModeFreeConnector( candidate ); } if( connector == nullptr ) { ... } encoder = drmModeGetEncoder( fd, connector->encoder_id ); if ( encoder == nullptr ) { ... } crtc = drmModeGetCrtc( fd, encoder->crtc_id ); if ( crtc == nullptr ) { ... } mreq.handle = creq.handle; if( drmIoctl( fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq ) ) { ... } pixels = mmap( 0, creq.size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, mreq.offset ); if( pixels == MAP_FAILED ) { ... } drmSetMaster( fd ); drmModeSetCrtc( fd, crtc->crtc_id, 0, 0, 0, nullptr, 0, nullptr ); drmModeSetCrtc( fd, crtc->crtc_id, fb, 0, 0, &connector->connector_id, 1, &connector->modes[ mode_index ] ); ͜ͷmmap͞ΕͨྖҬʹ ॻ͍ͨ಺༰͕ը໘ʹૹΒΕΔ dumb-bufferΛ࡞Δ
  13. /** * mipi_dbi_dev_init - MIPI DBI device initialization * @dbidev:

    MIPI DBI device structure to initialize * @funcs: Display pipe functions * @mode: Display mode * @rotation: Initial rotation in degrees Counter Clock Wise * * This function sets up a &drm_simple_display_pipe with a &drm_connector that * has one fixed &drm_display_mode which is rotated according to @rotation. * This mode is used to set the mode config min/max width/height properties. * Additionally &mipi_dbi.tx_buf is allocated. * * Supported formats: Native RGB565 and emulated XRGB8888. * * Returns: * Zero on success, negative error code on failure. */ int mipi_dbi_dev_init(struct mipi_dbi_dev *dbidev, const struct drm_simple_display_pipe_funcs *funcs, const struct drm_display_mode *mode, unsigned int rotation) { size_t bufsize = mode->vdisplay * mode->hdisplay * sizeof(u16); dbidev->drm.mode_config.preferred_depth = 16; return mipi_dbi_dev_init_with_formats(dbidev, funcs, mipi_dbi_formats, ARRAY_SIZE(mipi_dbi_formats), mode, rotation, bufsize); } Native RGB565 and emulated XRGB8888 ϐΫηϧϑΥʔϚοτ ͕࢖͑Δ RGB565 XRGB8888 drivers/gpu/drm/drm_mipi_dbi.c DRMଆ͸
  14. DRM_FORMAT_ 3 3 3 3 3 ( ( ( (

    ( ( # # # # # # # # # # # # # ( ( ( ( ( ( ( ( 3 3 3 3 3 3 3 3 DRM_FORMAT_ VK_FORMAT_R5G6B5_UNORM_PACK16 XRGB8888 RGB565 VK_FORMAT_B8G8R8A8_UNORM = = ͲͪΒͷܗࣜͰ΋Vulkanʹޓ׵ੑͷ͋ΔϑΥʔϚοτ͕͋Δ
  15. static void mipi_dbi_fb_dirty(struct iosys_map *src, struct drm_framebuffer *fb, struct drm_rect

    *rect) { struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev); unsigned int height = rect->y2 - rect->y1; unsigned int width = rect->x2 - rect->x1; struct mipi_dbi *dbi = &dbidev->dbi; bool swap = dbi->swap_bytes; int ret = 0; bool full; void *tr; full = width == fb->width && height == fb->height; DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect)); if (!dbi->dc || !full || swap || fb->format->format == DRM_FORMAT_XRGB8888) { tr = dbidev->tx_buf; ret = mipi_dbi_buf_copy(tr, src, fb, rect, swap); if (ret) goto err_msg; } else { tr = src->vaddr; /* TODO: Use mapping abstraction properly */ } mipi_dbi_set_window_address(dbidev, rect->x1, rect->x2 - 1, rect->y1, rect->y2 - 1); ret = mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START, tr, width * height * 2); err_msg: if (ret) drm_err_once(fb->dev, "Failed to update display %d\n", ret); } XRGB8888 ͩͬͨΒ SPIͰૹΔσʔλͷDMAόοϑΝʹ RGB565ʹม׵͠ͳ͕Βίϐʔ RGB565 ͩͬͨΒ Ϣʔβۭ͔ؒΒ ॻ͖ࠐΜͩόοϑΝ͕ ͦͷ··SPIͷDMAόοϑΝ drivers/gpu/drm/drm_mipi_dbi.c
  16. const auto external_memory_buffer_create_info = vk::ExternalMemoryBufferCreateInfo() .setHandleTypes( vk::ExternalMemoryHandleTypeFlagBits::eHostAllocationEXT ); props.setPNext( &external_memory_buffer_create_info

    ); auto buffer = device->createBuffer( props, nullptr ); const auto buffer_memory_requirement = device->getBufferMemoryRequirements( buffer ); const auto host_pointer_properties = device->getMemoryHostPointerPropertiesEXT( vk::ExternalMemoryHandleTypeFlagBits::eHostAllocationEXT, head.get() ); const auto host_pointer_info = vk::ImportMemoryHostPointerInfoEXT() .setHandleType( vk::ExternalMemoryHandleTypeFlagBits::eHostAllocationEXT ) .setPHostPointer( head.get() ); auto memory = device->allocateMemory( vk::MemoryAllocateInfo() .setPNext( &host_pointer_info ) .setAllocationSize( buffer_memory_requirement.size ) .setMemoryTypeIndex( std::countr_zero( host_pointer_properties.memoryTypeBits & buffer_memory_requirement.memoryTypeBits ) ), nullptr ); device->bindBufferMemory( buffer, memory, 0u ); VkBufferΛ࡞Δ ϝϞϦΛ֬อ͢Δ୅ΘΓʹ dumb-bufferͷઌ಄ΞυϨεΛ࢖͏ όοϑΝͱϝϞϦΛ݁ͼ͚ͭΔ
  17. command_buffer->beginRendering( vk::RenderingInfo() .setRenderArea( vk::Rect2D() .setExtent( vk::Extent2D() .setWidth( width ) .setHeight(

    height ) ) ) .setLayerCount( 1u ) .setColorAttachments( { color_rai } ) .setPDepthAttachment( &depth_rai ) .setPStencilAttachment( nullptr ) ); command_buffer->draw( vertex_count, 1u, 0u, 0u ); command_buffer->endRendering(); convert_image( command_buffer, ϨϯμϦϯά
  18. ); command_buffer->copyImageToBuffer( *color, vk::ImageLayout::eGeneral, *image_buffer, { vk::BufferImageCopy() .setBufferRowLength( width )

    .setBufferImageHeight( height ) .setImageSubresource( vk::ImageSubresourceLayers() .setAspectMask( vk::ImageAspectFlagBits::eColor ) .setLayerCount( 1u ) ) .setImageExtent( vk::Extent3D() .setWidth( width ) .setHeight( height ) .setDepth( 1u ) ) } ); ݁ՌΛdumb-bufferʹίϐʔ
  19. $ ./src/null_vb/render_to_null_vb Vulkan instance API version : 1.4.335 Vulkan device

    name : llvmpipe (LLVM 21.1.8, 128 bits) Vulkan device API version : 1.4.335 external_memory_host_properties.minImportedHostPointerAlignment : 4096 create_host_buffer size : 307200 alignment : 64 Segmentation fault ./src/null_vb/render_to_null_vb $ ./src/null_vb/render_to_null_vb Vulkan instance API version : 1.4.335 Vulkan device name : llvmpipe (LLVM 21.1.8, 256 bits) Vulkan device API version : 1.4.328 external_memory_host_properties.minImportedHostPointerAlignment : 4096 create_host_buffer size : 307200 alignment : 64 186, 186, 186 ... $ ./src/null_vb/render_to_null_vb Vulkan instance API version : 1.4.335 Vulkan device name : llvmpipe (LLVM 21.1.8, 128 bits) Vulkan device API version : 1.4.335 external_memory_host_properties.minImportedHostPointerAlignment : 4096 create_host_buffer size : 307200 alignment : 64 186, 186, 186 ... x86_64 AMD Ryzen 7 7745HX armv9-a CIX CD8180 armv7-a Rockchip RV1103 armv7-aͰ௖఺όοϑΝΛbind͢ΔͱԿނ͔SEGV͢Δ
  20. vec4 eye_pos; vec4 light_pos; vec4 base_color; float light_energy; float ambient;

    } uniforms; layout(binding = 1,std430) readonly buffer VertexBuffer { float data[]; } vertex_buffer; layout (location = 0) out vec3 output_color; out gl_PerVertex { vec4 gl_Position; }; vec3 eotf( vec3 v ) { return min( max( v / (v + 0.155 ) * 1.019, vec3( 0, 0, 0 ) ), vec3( 1, 1, 1 ) ); } void main() { vec3 input_position = vec3( vertex_buffer.data[ gl_VertexIndex * 6u + 0u ], vertex_buffer.data[ gl_VertexIndex * 6u + 1u ], vertex_buffer.data[ gl_VertexIndex * 6u + 2u ] ); vec3 input_normal = vec3( vertex_buffer.data[ gl_VertexIndex * 6u + 3u ], vertex_buffer.data[ gl_VertexIndex * 6u + 4u ], vertex_buffer.data[ gl_VertexIndex * 6u + 5u ] ); const vec4 local_pos = vec4( input_position.xyz, 1.0 ); const vec4 pos = uniforms.world_matrix * local_pos; ௖఺ͷ৘ใ͕ॻ͔Εͨ ετϨʔδόοϑΝ ௖఺γΣʔμʔͷεϨουIDʹ ରԠ͢Δ௖఺ͷ৘ใΛ ετϨʔδόοϑΝ͔ΒಡΉ shader.vert ௖఺όοϑΝΛ࢖Θͳ͍
  21. void main() { vec3 input_position = vec3( vertex_buffer.data[ gl_VertexIndex *

    6u + 0u ], vertex_buffer.data[ gl_VertexIndex * 6u + 1u ], vertex_buffer.data[ gl_VertexIndex * 6u + 2u ] ); vec3 input_normal = vec3( vertex_buffer.data[ gl_VertexIndex * 6u + 3u ], vertex_buffer.data[ gl_VertexIndex * 6u + 4u ], vertex_buffer.data[ gl_VertexIndex * 6u + 5u ] ); const vec4 local_pos = vec4( input_position.xyz, 1.0 ); const vec4 pos = uniforms.world_matrix * local_pos; const vec3 normal = normalize( mat3( uniforms.world_matrix) * input_normal ); const float pi = 3.141592653589793; const vec3 light_dir = normalize( uniforms.light_pos.xyz - pos.xyz ); const float diffuse = max( dot( light_dir, normal ), 0 ) /pi; output_color = eotf( ( uniforms.base_color.xyz * ( diffuse + uniforms.ambient ) ) * uniforms.light_energy ); gl_Position = uniforms.projection_camera_matrix * pos; } Ͱ͖Δ͚͍ͩܰγΣʔμʔ shader.vert #version 460 #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable layout (location = 0) in vec3 input_color; layout (location = 0) out vec4 output_color; void main() { output_color = vec4( input_color, 1.0 ); } shader.frag άʔϩʔγΣʔσΟϯά ֦ࢄޫ(ϥϯόʔτ)ͷΈ