mirror of
https://github.com/Kbz-8/Pulse.git
synced 2026-01-11 15:33:34 +00:00
working on software backend
This commit is contained in:
1
Examples/Software/.gitignore
vendored
git.filemode.normal_file
1
Examples/Software/.gitignore
vendored
git.filemode.normal_file
@@ -0,0 +1 @@
|
||||
*.spv.h
|
||||
@@ -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 !");
|
||||
|
||||
25
Examples/Software/shader.nzsl
git.filemode.normal_file
25
Examples/Software/shader.nzsl
git.filemode.normal_file
@@ -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);
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// This file is part of "Pulse"
|
||||
// For conditions of distribution and use, see copyright notice in LICENSE
|
||||
|
||||
#include <cpuinfo.h>
|
||||
|
||||
#include <Pulse.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -2,31 +2,89 @@
|
||||
// This file is part of "Pulse"
|
||||
// For conditions of distribution and use, see copyright notice in LICENSE
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <Pulse.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
|
||||
typedef struct SoftBuffer
|
||||
{
|
||||
void* buffer;
|
||||
void* map;
|
||||
PulseMapMode current_map_mode;
|
||||
} SoftBuffer;
|
||||
|
||||
PulseBuffer SoftCreateBuffer(PulseDevice device, const PulseBufferCreateInfo* create_infos);
|
||||
|
||||
@@ -2,19 +2,114 @@
|
||||
// This file is part of "Pulse"
|
||||
// For conditions of distribution and use, see copyright notice in LICENSE
|
||||
|
||||
#include <string.h>
|
||||
#include <stdatomic.h>
|
||||
#include <tinycthread.h>
|
||||
|
||||
#include <Pulse.h>
|
||||
#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 <stdio.h>
|
||||
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);
|
||||
}
|
||||
|
||||
95
Sources/Backends/Software/SoftCommandList.h
git.filemode.normal_file
95
Sources/Backends/Software/SoftCommandList.h
git.filemode.normal_file
@@ -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 <Pulse.h>
|
||||
|
||||
#ifdef PULSE_ENABLE_SOFTWARE_BACKEND
|
||||
|
||||
#ifndef PULSE_SOFTWARE_COMMAND_LIST_H_
|
||||
#define PULSE_SOFTWARE_COMMAND_LIST_H_
|
||||
|
||||
#include <tinycthread.h>
|
||||
|
||||
#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
|
||||
@@ -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 <Pulse.h>
|
||||
|
||||
#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
|
||||
@@ -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)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
typedef struct SoftComputePass
|
||||
{
|
||||
int dummy;
|
||||
} SoftComputePass;
|
||||
|
||||
PulseComputePass SoftCreateComputePass(PulseDevice device, PulseCommandList cmd);
|
||||
|
||||
@@ -2,15 +2,50 @@
|
||||
// This file is part of "Pulse"
|
||||
// For conditions of distribution and use, see copyright notice in LICENSE
|
||||
|
||||
#include <cpuinfo.h>
|
||||
|
||||
#include <Pulse.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -9,10 +9,13 @@
|
||||
#ifndef PULSE_SOFTWARE_DEVICE_H_
|
||||
#define PULSE_SOFTWARE_DEVICE_H_
|
||||
|
||||
#include <cpuinfo.h>
|
||||
|
||||
#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;
|
||||
|
||||
29
Sources/Backends/Software/SoftEnums.h
git.filemode.normal_file
29
Sources/Backends/Software/SoftEnums.h
git.filemode.normal_file
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user