From 211700b955732530e9c71322c0014dcb4b495997 Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Tue, 4 Mar 2025 00:13:32 +0100 Subject: [PATCH] working on software backend --- Examples/Software/.gitignore | 1 + Examples/Software/main.c | 45 ++++++++++ Examples/Software/shader.nzsl | 25 ++++++ Examples/Software/xmake.lua | 93 ++++++++++++++++++++ Sources/Backends/Software/Soft.c | 4 + Sources/Backends/Software/Soft.h | 2 +- Sources/Backends/Software/SoftBuffer.c | 58 ++++++++++++ Sources/Backends/Software/SoftBuffer.h | 2 + Sources/Backends/Software/SoftCommandList.c | 97 ++++++++++++++++++++- Sources/Backends/Software/SoftCommandList.h | 95 ++++++++++++++++++++ Sources/Backends/Software/SoftCommandlist.h | 24 ----- Sources/Backends/Software/SoftComputePass.c | 14 +++ Sources/Backends/Software/SoftComputePass.h | 1 + Sources/Backends/Software/SoftDevice.c | 35 ++++++++ Sources/Backends/Software/SoftDevice.h | 3 + Sources/Backends/Software/SoftEnums.h | 29 ++++++ Sources/Backends/Software/SoftFence.c | 35 ++++++++ Sources/Backends/WebGPU/WebGPUCommandList.c | 6 +- xmake.lua | 2 +- 19 files changed, 539 insertions(+), 32 deletions(-) create mode 100644 Examples/Software/.gitignore create mode 100644 Examples/Software/shader.nzsl create mode 100644 Sources/Backends/Software/SoftCommandList.h delete mode 100644 Sources/Backends/Software/SoftCommandlist.h create mode 100644 Sources/Backends/Software/SoftEnums.h diff --git a/Examples/Software/.gitignore b/Examples/Software/.gitignore new file mode 100644 index 0000000..289a601 --- /dev/null +++ b/Examples/Software/.gitignore @@ -0,0 +1 @@ +*.spv.h diff --git a/Examples/Software/main.c b/Examples/Software/main.c index a6ba17f..ada2add 100644 --- a/Examples/Software/main.c +++ b/Examples/Software/main.c @@ -16,12 +16,57 @@ void DebugCallBack(PulseDebugMessageSeverity severity, const char* message) printf("Pulse: %s\n", message); } +#define BUFFER_SIZE (256 * sizeof(uint32_t)) + int main(void) { PulseBackend backend = PulseLoadBackend(PULSE_BACKEND_SOFTWARE, PULSE_SHADER_FORMAT_SPIRV_BIT, PULSE_HIGH_DEBUG); PulseSetDebugCallback(backend, DebugCallBack); PulseDevice device = PulseCreateDevice(backend, NULL, 0); + PulseBufferCreateInfo buffer_create_info = { 0 }; + buffer_create_info.size = BUFFER_SIZE; + buffer_create_info.usage = PULSE_BUFFER_USAGE_STORAGE_READ | PULSE_BUFFER_USAGE_STORAGE_WRITE | PULSE_BUFFER_USAGE_TRANSFER_DOWNLOAD; + PulseBuffer buffer = PulseCreateBuffer(device, &buffer_create_info); + + // Get result and read it on CPU + { + PulseBufferCreateInfo staging_buffer_create_info = { 0 }; + staging_buffer_create_info.size = BUFFER_SIZE; + staging_buffer_create_info.usage = PULSE_BUFFER_USAGE_TRANSFER_UPLOAD | PULSE_BUFFER_USAGE_TRANSFER_DOWNLOAD; + PulseBuffer staging_buffer = PulseCreateBuffer(device, &staging_buffer_create_info); + + PulseFence fence = PulseCreateFence(device); + PulseCommandList cmd = PulseRequestCommandList(device, PULSE_COMMAND_LIST_TRANSFER_ONLY); + + PulseBufferRegion src_region = { 0 }; + src_region.buffer = buffer; + src_region.size = BUFFER_SIZE; + + PulseBufferRegion dst_region = { 0 }; + dst_region.buffer = staging_buffer; + dst_region.size = BUFFER_SIZE; + + PulseCopyBufferToBuffer(cmd, &src_region, &dst_region); + + PulseSubmitCommandList(device, cmd, fence); + PulseWaitForFences(device, &fence, 1, true); + + void* ptr; + PulseMapBuffer(staging_buffer, PULSE_MAP_READ, &ptr); + for(uint32_t i = 0; i < BUFFER_SIZE / sizeof(uint32_t); i++) + printf("%d, ", ((int32_t*)ptr)[i]); + puts(""); + PulseUnmapBuffer(staging_buffer); + + PulseDestroyBuffer(device, staging_buffer); + + PulseReleaseCommandList(device, cmd); + PulseDestroyFence(device, fence); + } + + PulseDestroyBuffer(device, buffer); + PulseDestroyDevice(device); PulseUnloadBackend(backend); puts("Successfully executed Pulse example using Software backend !"); diff --git a/Examples/Software/shader.nzsl b/Examples/Software/shader.nzsl new file mode 100644 index 0000000..7fd42e7 --- /dev/null +++ b/Examples/Software/shader.nzsl @@ -0,0 +1,25 @@ +[nzsl_version("1.0")] +module; + +struct Input +{ + [builtin(global_invocation_indices)] indices: vec3[u32] +} + +[layout(std430)] +struct SSBO +{ + data: dyn_array[i32] +} + +external +{ + [set(1), binding(0)] ssbo: storage[SSBO], +} + +[entry(compute)] +[workgroup(32, 32, 1)] +fn main(input: Input) +{ + ssbo.data[input.indices.x * input.indices.y] = i32(input.indices.x * input.indices.y); +} diff --git a/Examples/Software/xmake.lua b/Examples/Software/xmake.lua index 3f05ff9..ef43b42 100644 --- a/Examples/Software/xmake.lua +++ b/Examples/Software/xmake.lua @@ -1,7 +1,100 @@ +add_repositories("nazara-engine-repo https://github.com/NazaraEngine/xmake-repo") + +add_requires("nzsl >=2023.12.31", { configs = { shared = false, nzslc = true } }) + +if is_cross() then + add_requires("nzsl~host", { kind = "binary", host = true }) +end + +-- Yoinked from NZSL xmake repo +rule("find_nzsl") + on_config(function(target) + import("core.project.project") + import("core.tool.toolchain") + import("lib.detect.find_tool") + + local envs + if is_plat("windows") then + local msvc = target:toolchain("msvc") + if msvc and msvc:check() then + envs = msvc:runenvs() + end + elseif is_plat("mingw") then + local mingw = target:toolchain("mingw") + if mingw and mingw:check() then + envs = mingw:runenvs() + end + end + target:data_set("nzsl_envs", envs) + + local nzsl = project.required_package("nzsl~host") or project.required_package("nzsl") + local nzsldir + if nzsl then + nzsldir = path.join(nzsl:installdir(), "bin") + local osenvs = os.getenvs() + envs = envs or {} + for env, values in pairs(nzsl:get("envs")) do + local flatval = path.joinenv(values) + local oldenv = envs[env] or osenvs[env] + if not oldenv or oldenv == "" then + envs[env] = flatval + elseif not oldenv:startswith(flatval) then + envs[env] = flatval .. path.envsep() .. oldenv + end + end + end + + local nzsla = find_tool("nzsla", { version = true, paths = nzsldir, envs = envs }) + local nzslc = find_tool("nzslc", { version = true, paths = nzsldir, envs = envs }) + + target:data_set("nzsla", nzsla) + target:data_set("nzslc", nzslc) + target:data_set("nzsl_runenv", envs) + end) +rule_end() + +rule("compile_shaders") + set_extensions(".nzsl") + add_deps("find_nzsl") + + before_buildcmd_file(function(target, batchcmds, shaderfile, opt) + local outputdir = target:data("nzsl_includedirs") + local nzslc = target:data("nzslc") + local runenvs = target:data("nzsl_runenv") + assert(nzslc, "nzslc not found! please install nzsl package with nzslc enabled") + + batchcmds:show_progress(opt.progress, "${color.build.object}compiling.shader %s", shaderfile) + local argv = { "--compile=spv-header", "--optimize" } + if outputdir then + batchcmds:mkdir(outputdir) + table.insert(argv, "--output=" .. outputdir) + end + + local kind = target:data("plugin.project.kind") or "" + if kind:match("vs") then + table.insert(argv, "--log-format=vs") + end + + table.insert(argv, shaderfile) + + batchcmds:vrunv(nzslc.program, argv, { curdir = ".", envs = runenvs }) + + local outputfile = path.join(outputdir or path.directory(shaderfile), path.basename(shaderfile) .. ".spv.h") + + batchcmds:add_depfiles(shaderfile) + batchcmds:add_depvalues(nzslc.version) + batchcmds:set_depmtime(os.mtime(outputfile)) + batchcmds:set_depcache(target:dependfile(outputfile)) + end) +rule_end() + + target("SoftwareExample") add_deps("pulse_gpu") if is_plat("linux") then set_extension(".x86_64") end + add_rules("compile_shaders") add_files("*.c") + add_files("*.nzsl") target_end() diff --git a/Sources/Backends/Software/Soft.c b/Sources/Backends/Software/Soft.c index 930a6fa..827414c 100644 --- a/Sources/Backends/Software/Soft.c +++ b/Sources/Backends/Software/Soft.c @@ -2,6 +2,8 @@ // This file is part of "Pulse" // For conditions of distribution and use, see copyright notice in LICENSE +#include + #include #include "../../PulseInternal.h" @@ -21,11 +23,13 @@ bool SoftLoadBackend(PulseBackend backend, PulseDebugLevel debug_level) { PULSE_UNUSED(backend); PULSE_UNUSED(debug_level); + cpuinfo_initialize(); return true; } void SoftUnloadBackend(PulseBackend backend) { + cpuinfo_deinitialize(); free(backend->driver_data); } diff --git a/Sources/Backends/Software/Soft.h b/Sources/Backends/Software/Soft.h index 93008b3..4735da3 100644 --- a/Sources/Backends/Software/Soft.h +++ b/Sources/Backends/Software/Soft.h @@ -9,7 +9,7 @@ #ifndef PULSE_SOFTWARE_H_ #define PULSE_SOFTWARE_H_ -#define SOFTWARE_RETRIEVE_DRIVER_DATA_AS(handle, cast) ((cast)handle->driver_data) +#define SOFT_RETRIEVE_DRIVER_DATA_AS(handle, cast) ((cast)handle->driver_data) PulseBackendFlags SoftCheckSupport(PulseBackendFlags candidates, PulseShaderFormatsFlags shader_formats_used); // Return PULSE_BACKEND_SOFTWARE in case of success and PULSE_BACKEND_INVALID otherwise diff --git a/Sources/Backends/Software/SoftBuffer.c b/Sources/Backends/Software/SoftBuffer.c index 16ecb7b..457286c 100644 --- a/Sources/Backends/Software/SoftBuffer.c +++ b/Sources/Backends/Software/SoftBuffer.c @@ -2,31 +2,89 @@ // This file is part of "Pulse" // For conditions of distribution and use, see copyright notice in LICENSE +#include + #include #include "../../PulseInternal.h" #include "Soft.h" #include "SoftBuffer.h" +#include "SoftCommandList.h" PulseBuffer SoftCreateBuffer(PulseDevice device, const PulseBufferCreateInfo* create_infos) { + PulseBuffer buffer = (PulseBuffer)calloc(1, sizeof(PulseBufferHandler)); + PULSE_CHECK_ALLOCATION_RETVAL(buffer, PULSE_NULL_HANDLE); + + SoftBuffer* soft_buffer = (SoftBuffer*)calloc(1, sizeof(SoftBuffer) + _Alignof(SoftBuffer) + create_infos->size); + PULSE_CHECK_ALLOCATION_RETVAL(soft_buffer, PULSE_NULL_HANDLE); + + buffer->device = device; + buffer->driver_data = soft_buffer; + buffer->size = create_infos->size; + buffer->usage = create_infos->usage; + + soft_buffer->buffer = soft_buffer + sizeof(SoftBuffer) + _Alignof(SoftBuffer); + + return buffer; } bool SoftMapBuffer(PulseBuffer buffer, PulseMapMode mode, void** data) { + SoftBuffer* soft_buffer = SOFT_RETRIEVE_DRIVER_DATA_AS(buffer, SoftBuffer*); + + if(mode == PULSE_MAP_WRITE) + { + soft_buffer->map = calloc(1, buffer->size); + PULSE_CHECK_ALLOCATION_RETVAL(soft_buffer->map, false); + } + else + soft_buffer->map = soft_buffer->buffer; + if(soft_buffer->map == PULSE_NULLPTR) + return false; + soft_buffer->current_map_mode = mode; + *data = soft_buffer->map; + return true; } void SoftUnmapBuffer(PulseBuffer buffer) { + SoftBuffer* soft_buffer = SOFT_RETRIEVE_DRIVER_DATA_AS(buffer, SoftBuffer*); + if(soft_buffer->current_map_mode == PULSE_MAP_WRITE) + { + memcpy(soft_buffer->buffer, soft_buffer->map, buffer->size); + free(soft_buffer->map); + } + soft_buffer->map = PULSE_NULLPTR; } bool SoftCopyBufferToBuffer(PulseCommandList cmd, const PulseBufferRegion* src, const PulseBufferRegion* dst) { + SoftCommand command = { 0 }; + command.type = SOFT_COMMAND_COPY_BUFFER_TO_BUFFER; + command.CopyBufferToBuffer.src = (PulseBufferRegion*)malloc(sizeof(PulseBufferRegion)); + command.CopyBufferToBuffer.dst = (PulseBufferRegion*)malloc(sizeof(PulseBufferRegion)); + memcpy((void*)command.CopyBufferToBuffer.src, src, sizeof(PulseBufferRegion)); + memcpy((void*)command.CopyBufferToBuffer.dst, dst, sizeof(PulseBufferRegion)); + SoftQueueCommand(cmd, command); + return true; } bool SoftCopyBufferToImage(PulseCommandList cmd, const PulseBufferRegion* src, const PulseImageRegion* dst) { + SoftCommand command = { 0 }; + command.type = SOFT_COMMAND_COPY_BUFFER_TO_IMAGE; + command.CopyBufferToImage.src = (PulseBufferRegion*)malloc(sizeof(PulseBufferRegion)); + command.CopyBufferToImage.dst = (PulseImageRegion*)malloc(sizeof(PulseImageRegion)); + memcpy((void*)command.CopyBufferToImage.src, src, sizeof(PulseBufferRegion)); + memcpy((void*)command.CopyBufferToImage.dst, dst, sizeof(PulseImageRegion)); + SoftQueueCommand(cmd, command); + return true; } void SoftDestroyBuffer(PulseDevice device, PulseBuffer buffer) { + PULSE_UNUSED(device); + SoftBuffer* soft_buffer = SOFT_RETRIEVE_DRIVER_DATA_AS(buffer, SoftBuffer*); + free(soft_buffer); + free(buffer); } diff --git a/Sources/Backends/Software/SoftBuffer.h b/Sources/Backends/Software/SoftBuffer.h index 1caf437..5fb3ebe 100644 --- a/Sources/Backends/Software/SoftBuffer.h +++ b/Sources/Backends/Software/SoftBuffer.h @@ -13,7 +13,9 @@ typedef struct SoftBuffer { + void* buffer; void* map; + PulseMapMode current_map_mode; } SoftBuffer; PulseBuffer SoftCreateBuffer(PulseDevice device, const PulseBufferCreateInfo* create_infos); diff --git a/Sources/Backends/Software/SoftCommandList.c b/Sources/Backends/Software/SoftCommandList.c index 53fcb57..eb1ab4b 100644 --- a/Sources/Backends/Software/SoftCommandList.c +++ b/Sources/Backends/Software/SoftCommandList.c @@ -2,19 +2,114 @@ // This file is part of "Pulse" // For conditions of distribution and use, see copyright notice in LICENSE +#include +#include +#include + #include #include "../../PulseInternal.h" #include "Soft.h" -#include "SoftCommandlist.h" +#include "SoftFence.h" +#include "SoftDevice.h" +#include "SoftCommandList.h" +#include "SoftComputePass.h" +#include "SoftBuffer.h" + +static void SoftCommandCopyBufferToBuffer(SoftCommand* cmd) +{ + const PulseBufferRegion* src = cmd->CopyBufferToBuffer.src; + const PulseBufferRegion* dst = cmd->CopyBufferToBuffer.dst; + SoftBuffer* src_buffer = SOFT_RETRIEVE_DRIVER_DATA_AS(src->buffer, SoftBuffer*); + SoftBuffer* dst_buffer = SOFT_RETRIEVE_DRIVER_DATA_AS(dst->buffer, SoftBuffer*); + memcpy(dst_buffer->buffer + dst->offset, src_buffer->buffer + src->offset, (src->size < dst->size ? src->size : dst->size)); + //free((void*)src); + //free((void*)dst); +} + +static int SoftCommandsRunner(void* arg) +{ + PulseCommandList cmd = (PulseCommandList)arg; + PULSE_CHECK_PTR_RETVAL(cmd, 1); + + SoftCommandList* soft_cmd = SOFT_RETRIEVE_DRIVER_DATA_AS(cmd, SoftCommandList*); + PULSE_CHECK_PTR_RETVAL(soft_cmd, 1); + + for(uint32_t i = 0; i < soft_cmd->commands_count; i++) + { + SoftCommand* command = &soft_cmd->commands[i]; + switch(command->type) + { + case SOFT_COMMAND_BIND_COMPUTE_PIPELINE: break; + case SOFT_COMMAND_BIND_STORAGE_BUFFERS: break; + case SOFT_COMMAND_BIND_STORAGE_IMAGES: break; + case SOFT_COMMAND_BIND_UNIFORM_BUFFERS: break; + case SOFT_COMMAND_BLIT_IMAGES: break; + case SOFT_COMMAND_COPY_BUFFER_TO_BUFFER: SoftCommandCopyBufferToBuffer(command); break; + case SOFT_COMMAND_COPY_BUFFER_TO_IMAGE: break; + case SOFT_COMMAND_COPY_IMAGE_TO_BUFFER: break; + case SOFT_COMMAND_DISPATCH: break; + case SOFT_COMMAND_DISPATCH_INDIRECT: break; + + default: break; + } + } + + if(soft_cmd->fence != PULSE_NULL_HANDLE) + { + SoftFence* fence = SOFT_RETRIEVE_DRIVER_DATA_AS(soft_cmd->fence, SoftFence*); + atomic_store(&fence->signal, true); + } + cmd->state = PULSE_COMMAND_LIST_STATE_READY; + return 0; +} PulseCommandList SoftRequestCommandList(PulseDevice device, PulseCommandListUsage usage) { + PULSE_CHECK_HANDLE_RETVAL(device, PULSE_NULL_HANDLE); + + PULSE_UNUSED(usage); + + PulseCommandList cmd = (PulseCommandList)calloc(1, sizeof(PulseCommandListHandler)); + PULSE_CHECK_ALLOCATION_RETVAL(cmd, PULSE_NULL_HANDLE); + + SoftCommandList* soft_cmd = (SoftCommandList*)calloc(1, sizeof(SoftCommandList)); + PULSE_CHECK_ALLOCATION_RETVAL(soft_cmd, PULSE_NULL_HANDLE); + + cmd->usage = usage; + cmd->device = device; + cmd->driver_data = soft_cmd; + cmd->thread_id = PulseGetThreadID(); + + cmd->pass = SoftCreateComputePass(device, cmd); + cmd->state = PULSE_COMMAND_LIST_STATE_RECORDING; + cmd->is_available = false; + + return cmd; +} + +void SoftQueueCommand(PulseCommandList cmd, SoftCommand command) +{ + SoftCommandList* soft_cmd = SOFT_RETRIEVE_DRIVER_DATA_AS(cmd, SoftCommandList*); + PULSE_EXPAND_ARRAY_IF_NEEDED(soft_cmd->commands, SoftCommand, soft_cmd->commands_count, soft_cmd->commands_capacity, 8); + soft_cmd->commands[soft_cmd->commands_count] = command; + soft_cmd->commands_count++; } bool SoftSubmitCommandList(PulseDevice device, PulseCommandList cmd, PulseFence fence) { + PULSE_UNUSED(device); + SoftCommandList* soft_cmd = SOFT_RETRIEVE_DRIVER_DATA_AS(cmd, SoftCommandList*); + cmd->state = PULSE_COMMAND_LIST_STATE_SENT; + soft_cmd->fence = fence; + return thrd_create(&soft_cmd->thread, SoftCommandsRunner, cmd) == thrd_success; } +#include void SoftReleaseCommandList(PulseDevice device, PulseCommandList cmd) { + SoftCommandList* soft_cmd = SOFT_RETRIEVE_DRIVER_DATA_AS(cmd, SoftCommandList*); + printf("%p, %p, %p\n", cmd, soft_cmd, cmd->pass); + SoftDestroyComputePass(device, cmd->pass); + free(soft_cmd); + free(cmd); } diff --git a/Sources/Backends/Software/SoftCommandList.h b/Sources/Backends/Software/SoftCommandList.h new file mode 100644 index 0000000..f757a8e --- /dev/null +++ b/Sources/Backends/Software/SoftCommandList.h @@ -0,0 +1,95 @@ +// Copyright (C) 2025 kanel +// This file is part of "Pulse" +// For conditions of distribution and use, see copyright notice in LICENSE + +#include + +#ifdef PULSE_ENABLE_SOFTWARE_BACKEND + +#ifndef PULSE_SOFTWARE_COMMAND_LIST_H_ +#define PULSE_SOFTWARE_COMMAND_LIST_H_ + +#include + +#include "Soft.h" +#include "SoftEnums.h" +#include "SoftFence.h" + +typedef struct SoftCommand +{ + SoftCommandType type; + union + { + struct + { + PulseComputePipeline pipeline; + } BindComputePipeline; + + struct + { + } BindStorageBuffers; + + struct + { + } BindStorageImages; + + struct + { + } BindUniformBuffers; + + struct + { + const PulseImageRegion* src; + const PulseImageRegion* dst; + } BlitImages; + + struct + { + const PulseBufferRegion* src; + const PulseBufferRegion* dst; + } CopyBufferToBuffer; + + struct + { + const PulseBufferRegion* src; + const PulseImageRegion* dst; + } CopyBufferToImage; + + struct + { + const PulseImageRegion* src; + const PulseBufferRegion* dst; + } CopyImageToBuffer; + + struct + { + uint32_t groupcount_x; + uint32_t groupcount_y; + uint32_t groupcount_z; + } Dispatch; + + struct + { + PulseBuffer buffer; + uint32_t offset; + } DispatchIndirect; + }; +} SoftCommand; + +typedef struct SoftCommandList +{ + thrd_t thread; + PulseFence fence; + SoftCommand* commands; + uint32_t commands_count; + uint32_t commands_capacity; +} SoftCommandList; + +PulseCommandList SoftRequestCommandList(PulseDevice device, PulseCommandListUsage usage); +void SoftQueueCommand(PulseCommandList cmd, SoftCommand command); +bool SoftSubmitCommandList(PulseDevice device, PulseCommandList cmd, PulseFence fence); +void SoftReleaseCommandList(PulseDevice device, PulseCommandList cmd); + +#endif // PULSE_SOFTWARE_COMMAND_LIST_H_ + +#endif // PULSE_ENABLE_SOFTWARE_BACKEND diff --git a/Sources/Backends/Software/SoftCommandlist.h b/Sources/Backends/Software/SoftCommandlist.h deleted file mode 100644 index 16c5ef6..0000000 --- a/Sources/Backends/Software/SoftCommandlist.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2025 kanel -// This file is part of "Pulse" -// For conditions of distribution and use, see copyright notice in LICENSE - -#include - -#ifdef PULSE_ENABLE_SOFTWARE_BACKEND - -#ifndef PULSE_SOFTWARE_COMMAND_LIST_H_ -#define PULSE_SOFTWARE_COMMAND_LIST_H_ - -#include "Soft.h" - -typedef struct SoftCommandList -{ -} SoftCommandList; - -PulseCommandList SoftRequestCommandList(PulseDevice device, PulseCommandListUsage usage); -bool SoftSubmitCommandList(PulseDevice device, PulseCommandList cmd, PulseFence fence); -void SoftReleaseCommandList(PulseDevice device, PulseCommandList cmd); - -#endif // PULSE_SOFTWARE_COMMAND_LIST_H_ - -#endif // PULSE_ENABLE_SOFTWARE_BACKEND diff --git a/Sources/Backends/Software/SoftComputePass.c b/Sources/Backends/Software/SoftComputePass.c index 1578ee8..6034125 100644 --- a/Sources/Backends/Software/SoftComputePass.c +++ b/Sources/Backends/Software/SoftComputePass.c @@ -9,10 +9,24 @@ PulseComputePass SoftCreateComputePass(PulseDevice device, PulseCommandList cmd) { + PULSE_UNUSED(device); + PulseComputePass pass = (PulseComputePass)calloc(1, sizeof(PulseComputePassHandler)); + PULSE_CHECK_ALLOCATION_RETVAL(pass, PULSE_NULL_HANDLE); + + SoftComputePass* soft_pass = (SoftComputePass*)calloc(1, sizeof(SoftComputePass)); + PULSE_CHECK_ALLOCATION_RETVAL(soft_pass, PULSE_NULL_HANDLE); + + pass->cmd = cmd; + pass->driver_data = soft_pass; + + return pass; } void SoftDestroyComputePass(PulseDevice device, PulseComputePass pass) { + PULSE_UNUSED(device); + free(pass->driver_data); + free(pass); } PulseComputePass SoftBeginComputePass(PulseCommandList cmd) diff --git a/Sources/Backends/Software/SoftComputePass.h b/Sources/Backends/Software/SoftComputePass.h index d3f0e68..39a56bf 100644 --- a/Sources/Backends/Software/SoftComputePass.h +++ b/Sources/Backends/Software/SoftComputePass.h @@ -13,6 +13,7 @@ typedef struct SoftComputePass { + int dummy; } SoftComputePass; PulseComputePass SoftCreateComputePass(PulseDevice device, PulseCommandList cmd); diff --git a/Sources/Backends/Software/SoftDevice.c b/Sources/Backends/Software/SoftDevice.c index fb4d48b..e182066 100644 --- a/Sources/Backends/Software/SoftDevice.c +++ b/Sources/Backends/Software/SoftDevice.c @@ -2,15 +2,50 @@ // This file is part of "Pulse" // For conditions of distribution and use, see copyright notice in LICENSE +#include + #include #include "../../PulseInternal.h" #include "Soft.h" +#include "SoftComputePipeline.h" +#include "SoftCommandList.h" #include "SoftDevice.h" +#include "SoftFence.h" +#include "SoftBuffer.h" +#include "SoftImage.h" +#include "SoftComputePass.h" PulseDevice SoftCreateDevice(PulseBackend backend, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count) { + PULSE_UNUSED(forbiden_devices); + PULSE_UNUSED(forbiden_devices_count); + + PULSE_CHECK_HANDLE_RETVAL(backend, PULSE_NULLPTR); + + PulseDevice pulse_device = (PulseDeviceHandler*)calloc(1, sizeof(PulseDeviceHandler)); + PULSE_CHECK_ALLOCATION_RETVAL(pulse_device, PULSE_NULL_HANDLE); + + SoftDevice* device = (SoftDevice*)calloc(1, sizeof(SoftDevice)); + PULSE_CHECK_ALLOCATION_RETVAL(device, PULSE_NULL_HANDLE); + + device->device = cpuinfo_get_current_processor(); + + pulse_device->driver_data = device; + pulse_device->backend = backend; + PULSE_LOAD_DRIVER_DEVICE(Soft); + + if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(backend)) + PulseLogInfoFmt(backend, "(Soft) created device from %s", device->device->package->name); + return pulse_device; } void SoftDestroyDevice(PulseDevice device) { + SoftDevice* soft_device = SOFT_RETRIEVE_DRIVER_DATA_AS(device, SoftDevice*); + if(soft_device == PULSE_NULLPTR) + return; + if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(device->backend)) + PulseLogInfoFmt(device->backend, "(Soft) destroyed device created from %s", soft_device->device->package->name); + free(soft_device); + free(device); } diff --git a/Sources/Backends/Software/SoftDevice.h b/Sources/Backends/Software/SoftDevice.h index 2e1d859..f4f08ac 100644 --- a/Sources/Backends/Software/SoftDevice.h +++ b/Sources/Backends/Software/SoftDevice.h @@ -9,10 +9,13 @@ #ifndef PULSE_SOFTWARE_DEVICE_H_ #define PULSE_SOFTWARE_DEVICE_H_ +#include + #include "Soft.h" typedef struct SoftDevice { + const struct cpuinfo_processor* device; PulseCommandList* available_command_lists; uint32_t available_command_lists_capacity; uint32_t available_command_lists_size; diff --git a/Sources/Backends/Software/SoftEnums.h b/Sources/Backends/Software/SoftEnums.h new file mode 100644 index 0000000..c1ed127 --- /dev/null +++ b/Sources/Backends/Software/SoftEnums.h @@ -0,0 +1,29 @@ +// Copyright (C) 2025 kanel +// This file is part of "Pulse" +// For conditions of distribution and use, see copyright notice in LICENSE + +#ifdef PULSE_ENABLE_SOFTWARE_BACKEND + +#ifndef PULSE_SOFTWARE_ENUMS_H_ +#define PULSE_SOFTWARE_ENUMS_H_ + +typedef enum SoftCommandType +{ + SOFT_COMMAND_NONE = 0, + SOFT_COMMAND_BIND_COMPUTE_PIPELINE, + SOFT_COMMAND_BIND_STORAGE_BUFFERS, + SOFT_COMMAND_BIND_STORAGE_IMAGES, + SOFT_COMMAND_BIND_UNIFORM_BUFFERS, + SOFT_COMMAND_BLIT_IMAGES, + SOFT_COMMAND_COPY_BUFFER_TO_BUFFER, + SOFT_COMMAND_COPY_BUFFER_TO_IMAGE, + SOFT_COMMAND_COPY_IMAGE_TO_BUFFER, + SOFT_COMMAND_DISPATCH, + SOFT_COMMAND_DISPATCH_INDIRECT, + + SOFT_COMMAND_END_ENUM // For internal use only +} SoftCommandType; + +#endif // PULSE_SOFTWARE_ENUMS_H_ + +#endif // PULSE_ENABLE_SOFTWARE_BACKEND diff --git a/Sources/Backends/Software/SoftFence.c b/Sources/Backends/Software/SoftFence.c index 8d1eae2..77512e2 100644 --- a/Sources/Backends/Software/SoftFence.c +++ b/Sources/Backends/Software/SoftFence.c @@ -9,16 +9,51 @@ PulseFence SoftCreateFence(PulseDevice device) { + PULSE_UNUSED(device); + + PulseFence fence = (PulseFence)calloc(1, sizeof(PulseFence)); + PULSE_CHECK_ALLOCATION_RETVAL(fence, PULSE_NULL_HANDLE); + + SoftFence* soft_fence = (SoftFence*)calloc(1, sizeof(SoftFence)); + PULSE_CHECK_ALLOCATION_RETVAL(soft_fence, PULSE_NULL_HANDLE); + + atomic_store(&soft_fence->signal, true); + + fence->driver_data = soft_fence; + + return fence; } void SoftDestroyFence(PulseDevice device, PulseFence fence) { + PULSE_UNUSED(device); + free(fence->driver_data); + free(fence); } bool SoftIsFenceReady(PulseDevice device, PulseFence fence) { + PULSE_UNUSED(device); + SoftFence* soft_fence = SOFT_RETRIEVE_DRIVER_DATA_AS(fence, SoftFence*); + return atomic_load(&soft_fence->signal); } bool SoftWaitForFences(PulseDevice device, const PulseFence* fences, uint32_t fences_count, bool wait_for_all) { + PULSE_UNUSED(device); + if(fences_count == 0) + return true; + uint32_t fences_to_wait = fences_count; + while(fences_to_wait != 0) + { + for(uint32_t i = 0; i < fences_count; i++) + { + if(SoftIsFenceReady(device, fences[i])) + fences_to_wait--; + } + if(!wait_for_all && fences_to_wait != fences_count) + return true; + PulseSleep(1); // 1ms + } + return true; } diff --git a/Sources/Backends/WebGPU/WebGPUCommandList.c b/Sources/Backends/WebGPU/WebGPUCommandList.c index c06c22b..c18c4b3 100644 --- a/Sources/Backends/WebGPU/WebGPUCommandList.c +++ b/Sources/Backends/WebGPU/WebGPUCommandList.c @@ -84,15 +84,11 @@ bool WebGPUSubmitCommandList(PulseDevice device, PulseCommandList cmd, PulseFenc void WebGPUReleaseCommandList(PulseDevice device, PulseCommandList cmd) { - PULSE_CHECK_HANDLE(device); - WebGPUCommandList* webgpu_cmd = WEBGPU_RETRIEVE_DRIVER_DATA_AS(cmd, WebGPUCommandList*); - WebGPUComputePass* webgpu_pass = WEBGPU_RETRIEVE_DRIVER_DATA_AS(cmd->pass, WebGPUComputePass*); wgpuCommandEncoderRelease(webgpu_cmd->encoder); - free(webgpu_pass); - free(cmd->pass); + WebGPUDestroyComputePass(device, cmd->pass); free(webgpu_cmd); free(cmd); } diff --git a/xmake.lua b/xmake.lua index 493624f..a88b46c 100644 --- a/xmake.lua +++ b/xmake.lua @@ -33,7 +33,7 @@ local backends = { Software = { option = "software", default = true, - packages = { "spirv-vm", "openmp", "cpuinfo" } + packages = { "spirv-vm", "cpuinfo" } } }