working on software backend

This commit is contained in:
2025-03-04 00:13:32 +01:00
parent 8c7b2bb44f
commit 211700b955
19 changed files with 539 additions and 32 deletions

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -13,7 +13,9 @@
typedef struct SoftBuffer
{
void* buffer;
void* map;
PulseMapMode current_map_mode;
} SoftBuffer;
PulseBuffer SoftCreateBuffer(PulseDevice device, const PulseBufferCreateInfo* create_infos);

View File

@@ -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
View 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

View File

@@ -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

View File

@@ -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)

View File

@@ -13,6 +13,7 @@
typedef struct SoftComputePass
{
int dummy;
} SoftComputePass;
PulseComputePass SoftCreateComputePass(PulseDevice device, PulseCommandList cmd);

View File

@@ -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);
}

View File

@@ -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
View 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

View File

@@ -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;
}