From 849fc458e2dffc7c68d15258b4f66a9105faa865 Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Sun, 6 Apr 2025 20:00:20 +0200 Subject: [PATCH] implementing opengl binds group --- Examples/OpenGL/main.c | 2 +- Sources/Backends/OpenGL/OpenGLBindsGroup.c | 209 ++++++++++++++++++ Sources/Backends/OpenGL/OpenGLBindsGroup.h | 113 ++++++++++ Sources/Backends/OpenGL/OpenGLCommandList.c | 41 ++++ Sources/Backends/OpenGL/OpenGLCommandList.h | 8 + Sources/Backends/OpenGL/OpenGLComputePass.c | 120 +++++++++- Sources/Backends/OpenGL/OpenGLComputePass.h | 9 +- .../Backends/OpenGL/OpenGLComputePipeline.c | 33 ++- .../Backends/OpenGL/OpenGLComputePipeline.h | 4 + Sources/Backends/OpenGL/OpenGLDevice.c | 11 +- Sources/Backends/OpenGL/OpenGLDevice.h | 4 + Sources/Backends/OpenGL/OpenGLEnums.h | 9 + Sources/Backends/Vulkan/VulkanDescriptor.c | 5 +- 13 files changed, 560 insertions(+), 8 deletions(-) create mode 100644 Sources/Backends/OpenGL/OpenGLBindsGroup.c create mode 100644 Sources/Backends/OpenGL/OpenGLBindsGroup.h diff --git a/Examples/OpenGL/main.c b/Examples/OpenGL/main.c index da81c5a..bb80278 100644 --- a/Examples/OpenGL/main.c +++ b/Examples/OpenGL/main.c @@ -63,7 +63,7 @@ int main(int ac, char** av) PulseCommandList cmd = PulseRequestCommandList(device, PULSE_COMMAND_LIST_GENERAL); PulseComputePass pass = PulseBeginComputePass(cmd); - //PulseBindStorageBuffers(pass, &buffer, 1); + PulseBindStorageBuffers(pass, &buffer, 1); PulseBindComputePipeline(pass, pipeline); PulseDispatchComputations(pass, 16, 1, 1); PulseEndComputePass(pass); diff --git a/Sources/Backends/OpenGL/OpenGLBindsGroup.c b/Sources/Backends/OpenGL/OpenGLBindsGroup.c new file mode 100644 index 0000000..21caa29 --- /dev/null +++ b/Sources/Backends/OpenGL/OpenGLBindsGroup.c @@ -0,0 +1,209 @@ +// Copyright (C) 2025 kanel +// This file is part of "Pulse" +// For conditions of distribution and use, see copyright notice in LICENSE + +#include + +#include + +#include "OpenGL.h" +#include "OpenGLBindsGroup.h" +#include "OpenGLDevice.h" + +void OpenGLInitBindsGroupLayoutManager(OpenGLBindsGroupLayoutManager* manager, PulseDevice device) +{ + memset(manager, 0, sizeof(OpenGLBindsGroupLayoutManager)); + manager->device = device; +} + +OpenGLBindsGroupLayout* OpenGLGetBindsGroupLayout(OpenGLBindsGroupLayoutManager* manager, + uint32_t read_storage_images_count, + uint32_t read_storage_buffers_count, + uint32_t write_storage_images_count, + uint32_t write_storage_buffers_count, + uint32_t uniform_buffers_count) +{ + for(uint32_t i = 0; i < manager->layouts_size; i++) + { + OpenGLBindsGroupLayout* layout = manager->layouts[i]; + if( layout->ReadOnly.storage_buffer_count == read_storage_buffers_count && + layout->ReadOnly.storage_texture_count == read_storage_images_count && + layout->ReadWrite.storage_buffer_count == write_storage_buffers_count && + layout->ReadWrite.storage_texture_count == write_storage_images_count && + layout->Uniform.buffer_count == uniform_buffers_count) + { + return layout; + } + } + + PULSE_EXPAND_ARRAY_IF_NEEDED(manager->layouts, OpenGLBindsGroupLayout*, manager->layouts_size, manager->layouts_capacity, 1); + PULSE_CHECK_ALLOCATION_RETVAL(manager->layouts, PULSE_NULLPTR); + + OpenGLBindsGroupLayout* layout = (OpenGLBindsGroupLayout*)malloc(sizeof(OpenGLBindsGroupLayout)); + manager->layouts[manager->layouts_size] = layout; + manager->layouts_size++; + + if(uniform_buffers_count != 0) + layout->type = OPENGL_BINDS_GROUP_UNIFORM; + else if(write_storage_images_count != 0 || write_storage_buffers_count != 0) + layout->type = OPENGL_BINDS_GROUP_READ_WRITE; + else + layout->type = OPENGL_BINDS_GROUP_READ_ONLY; + + layout->ReadOnly.storage_buffer_count = read_storage_buffers_count; + layout->ReadOnly.storage_texture_count = read_storage_images_count; + layout->ReadWrite.storage_buffer_count = write_storage_buffers_count; + layout->ReadWrite.storage_texture_count = write_storage_images_count; + layout->Uniform.buffer_count = uniform_buffers_count; + + return layout; +} + +void OpenGLDestroyBindsGroupLayoutManager(OpenGLBindsGroupLayoutManager* manager) +{ + for(uint32_t i = 0; i < manager->layouts_size; i++) + free(manager->layouts[i]); + free(manager->layouts); + memset(manager, 0, sizeof(OpenGLBindsGroupPoolManager)); +} + +OpenGLBindsGroup* OpenGLRequestBindsGroupFromPool(OpenGLBindsGroupPool* pool, const OpenGLBindsGroupLayout* layout) +{ + for(size_t i = 0; i < OPENGL_POOL_SIZE; i++) + { + if(pool->free_groups[i] == PULSE_NULLPTR) + break; // Due to defragmentation we are sure not to find valid groups after the first NULL one + if(pool->free_groups[i]->layout == layout) + { + OpenGLBindsGroup* group = pool->free_groups[i]; + PULSE_DEFRAG_ARRAY(pool->free_groups, OPENGL_POOL_SIZE, i); + pool->free_index--; + pool->used_groups[pool->used_index] = group; + pool->used_index++; + return group; + } + } + + OpenGLBindsGroup* group = (OpenGLBindsGroup*)calloc(1, sizeof(OpenGLBindsGroup)); + PULSE_CHECK_ALLOCATION_RETVAL(group, PULSE_NULLPTR); + + group->layout = (OpenGLBindsGroupLayout*)layout; + group->pool = pool; + group->type = layout->type; + if(layout->type == OPENGL_BINDS_GROUP_READ_ONLY) + { + group->ReadOnly.storage_buffers = (PulseBuffer*)calloc(layout->ReadOnly.storage_buffer_count + 1, sizeof(PulseBuffer)); + group->ReadOnly.images = (PulseImage*)calloc(layout->ReadOnly.storage_texture_count + 1, sizeof(PulseImage)); + } + else if(layout->type == OPENGL_BINDS_GROUP_READ_WRITE) + { + group->ReadWrite.storage_buffers = (PulseBuffer*)calloc(layout->ReadWrite.storage_buffer_count + 1, sizeof(PulseBuffer)); + group->ReadWrite.images = (PulseImage*)calloc(layout->ReadWrite.storage_texture_count + 1, sizeof(PulseImage)); + } + else if(layout->type == OPENGL_BINDS_GROUP_UNIFORM) + group->Uniform.buffers = (PulseBuffer*)calloc(layout->Uniform.buffer_count + 1, sizeof(PulseBuffer)); + + pool->used_groups[pool->used_index] = group; + pool->used_index++; + + pool->allocations_count++; + return group; +} + +void OpenGLReturnBindsGroupToPool(OpenGLBindsGroupPool* pool, const OpenGLBindsGroup* group) +{ + for(size_t i = 0; i < OPENGL_POOL_SIZE; i++) + { + if(pool->used_groups[i] == PULSE_NULLPTR) + break; // Due to defragmentation we are sure not to find valid groups after the first NULL one + if(pool->used_groups[i] == group) + { + PULSE_DEFRAG_ARRAY(pool->used_groups, OPENGL_POOL_SIZE, i); + pool->used_index--; + pool->free_groups[pool->free_index] = (OpenGLBindsGroup*)group; + pool->free_index++; + return; + } + } +} + +void OpenGLInitBindsGroupPool(OpenGLBindsGroupPool* pool, PulseDevice device) +{ + memset(pool, 0, sizeof(OpenGLBindsGroupPool)); + pool->device = device; + pool->thread_id = PulseGetThreadID(); +} + +void OpenGLDestroyBindsGroup(OpenGLBindsGroup* group) +{ + if(group->type == OPENGL_BINDS_GROUP_READ_ONLY) + { + free(group->ReadOnly.storage_buffers); + free(group->ReadOnly.images); + } + else if(group->type == OPENGL_BINDS_GROUP_READ_WRITE) + { + free(group->ReadWrite.storage_buffers); + free(group->ReadWrite.images); + } + else if(group->type == OPENGL_BINDS_GROUP_UNIFORM) + free(group->Uniform.buffers); +} + +void OpenGLDestroyBindsGroupPool(OpenGLBindsGroupPool* pool) +{ + for(size_t i = 0; i < OPENGL_POOL_SIZE; i++) + { + if(pool->used_groups[i] != PULSE_NULLPTR) + { + OpenGLDestroyBindsGroup(pool->used_groups[i]); + free(pool->used_groups[i]); + pool->used_groups[i] = PULSE_NULLPTR; + } + if(pool->free_groups[i] != PULSE_NULLPTR) + { + OpenGLDestroyBindsGroup(pool->free_groups[i]); + free(pool->free_groups[i]); + pool->free_groups[i] = PULSE_NULLPTR; + } + if(pool->free_groups[i] == PULSE_NULLPTR && pool->used_groups[i] == PULSE_NULLPTR) + break; // Due to defragmentation we are sure not to find valid groups after the first NULL one + } + memset(pool, 0, sizeof(OpenGLBindsGroupPool)); +} + +void OpenGLInitBindsGroupPoolManager(OpenGLBindsGroupPoolManager* manager, PulseDevice device) +{ + memset(manager, 0, sizeof(OpenGLBindsGroupPoolManager)); + manager->device = device; +} + +OpenGLBindsGroupPool* OpenGLGetAvailableBindsGroupPool(OpenGLBindsGroupPoolManager* manager) +{ + PulseThreadID thread_id = PulseGetThreadID(); + for(uint32_t i = 0; i < manager->pools_size; i++) + { + if(thread_id == manager->pools[i]->thread_id && (manager->pools[i]->allocations_count < OPENGL_POOL_SIZE || manager->pools[i]->free_groups[0] != PULSE_NULLPTR)) + return manager->pools[i]; + } + PULSE_EXPAND_ARRAY_IF_NEEDED(manager->pools, OpenGLBindsGroupPool*, manager->pools_size, manager->pools_capacity, 1); + PULSE_CHECK_ALLOCATION_RETVAL(manager->pools, PULSE_NULLPTR); + + manager->pools[manager->pools_size] = (OpenGLBindsGroupPool*)calloc(1, sizeof(OpenGLBindsGroupPool)); + PULSE_CHECK_ALLOCATION_RETVAL(manager->pools[manager->pools_size], PULSE_NULLPTR); + + OpenGLInitBindsGroupPool(manager->pools[manager->pools_size], manager->device); + manager->pools_size++; + return manager->pools[manager->pools_size - 1]; +} + +void OpenGLDestroyBindsGroupPoolManager(OpenGLBindsGroupPoolManager* manager) +{ + for(uint32_t i = 0; i < manager->pools_size; i++) + { + OpenGLDestroyBindsGroupPool(manager->pools[i]); + free(manager->pools[i]); + } + free(manager->pools); + memset(manager, 0, sizeof(OpenGLBindsGroupPoolManager)); +} diff --git a/Sources/Backends/OpenGL/OpenGLBindsGroup.h b/Sources/Backends/OpenGL/OpenGLBindsGroup.h new file mode 100644 index 0000000..46d50a5 --- /dev/null +++ b/Sources/Backends/OpenGL/OpenGLBindsGroup.h @@ -0,0 +1,113 @@ +// 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_OPENGL_BACKEND + +#ifndef PULSE_OPENGL_BINDGROUPS_H_ +#define PULSE_OPENGL_BINDGROUPS_H_ + +#include +#include "OpenGL.h" +#include "OpenGLEnums.h" +#include "../../PulseInternal.h" + +#define OPENGL_POOL_SIZE 128 + +typedef struct OpenGLBindsGroupLayout +{ + union + { + struct + { + uint32_t storage_buffer_count; + uint32_t storage_texture_count; + } ReadOnly; + struct + { + uint32_t storage_buffer_count; + uint32_t storage_texture_count; + } ReadWrite; + struct + { + uint32_t buffer_count; + } Uniform; + }; + + OpenGLBindsGroupType type; +} OpenGLBindsGroupLayout; + +typedef struct OpenGLBindsGroup +{ + union + { + // NULL terminated arrays + struct + { + PulseBuffer* storage_buffers; + PulseImage* images; + } ReadOnly; + struct + { + PulseBuffer* storage_buffers; + PulseImage* images; + } ReadWrite; + struct + { + PulseBuffer* buffers; + } Uniform; + }; + + OpenGLBindsGroupType type; + OpenGLBindsGroupLayout* layout; + struct OpenGLBindsGroupPool* pool; +} OpenGLBindsGroup; + +typedef struct OpenGLBindsGroupLayoutManager +{ + PulseDevice device; + OpenGLBindsGroupLayout** layouts; + uint32_t layouts_capacity; + uint32_t layouts_size; +} OpenGLBindsGroupLayoutManager; + +typedef struct OpenGLBindsGroupPool +{ + OpenGLBindsGroup* used_groups[OPENGL_POOL_SIZE]; + OpenGLBindsGroup* free_groups[OPENGL_POOL_SIZE]; + uint32_t used_index; + uint32_t free_index; + PulseDevice device; + PulseThreadID thread_id; + uint32_t allocations_count; +} OpenGLBindsGroupPool; + +typedef struct OpenGLBindsGroupPoolManager +{ + PulseDevice device; + OpenGLBindsGroupPool** pools; + uint32_t pools_capacity; + uint32_t pools_size; +} OpenGLBindsGroupPoolManager; + +void OpenGLInitBindsGroupLayoutManager(OpenGLBindsGroupLayoutManager* manager, PulseDevice device); +OpenGLBindsGroupLayout* OpenGLGetBindsGroupLayout(OpenGLBindsGroupLayoutManager* manager, + uint32_t read_storage_images_count, + uint32_t read_storage_buffers_count, + uint32_t write_storage_images_count, + uint32_t write_storage_buffers_count, + uint32_t uniform_buffers_count); +void OpenGLDestroyBindsGroupLayoutManager(OpenGLBindsGroupLayoutManager* manager); + +OpenGLBindsGroup* OpenGLRequestBindsGroupFromPool(OpenGLBindsGroupPool* pool, const OpenGLBindsGroupLayout* layout); +void OpenGLReturnBindsGroupToPool(OpenGLBindsGroupPool* pool, const OpenGLBindsGroup* group); + +void OpenGLInitBindsGroupPoolManager(OpenGLBindsGroupPoolManager* manager, PulseDevice device); +OpenGLBindsGroupPool* OpenGLGetAvailableBindsGroupPool(OpenGLBindsGroupPoolManager* manager); +void OpenGLDestroyBindsGroupPoolManager(OpenGLBindsGroupPoolManager* manager); + +#endif // PULSE_OPENGL_BINDGROUPS_H_ + +#endif // PULSE_ENABLE_OPENGL_BACKEND diff --git a/Sources/Backends/OpenGL/OpenGLCommandList.c b/Sources/Backends/OpenGL/OpenGLCommandList.c index 36dae2d..7819acc 100644 --- a/Sources/Backends/OpenGL/OpenGLCommandList.c +++ b/Sources/Backends/OpenGL/OpenGLCommandList.c @@ -34,8 +34,49 @@ static void OpenGLCommandDispatch(PulseDevice device, OpenGLCommand* cmd) { OpenGLDevice* opengl_device = OPENGL_RETRIEVE_DRIVER_DATA_AS(device, OpenGLDevice*); OpenGLComputePipeline* opengl_pipeline = OPENGL_RETRIEVE_DRIVER_DATA_AS(cmd->Dispatch.pipeline, OpenGLComputePipeline*); + opengl_device->glUseProgram(device, opengl_pipeline->program); + + uint32_t buffer_index = 0; + uint32_t image_index = 0; + + if(cmd->Dispatch.read_only_group != PULSE_NULLPTR) + { + for(uint32_t i = 0; cmd->Dispatch.read_only_group->ReadOnly.images[i] != PULSE_NULLPTR; i++, image_index++) + { + PulseImage image = cmd->Dispatch.read_only_group->ReadOnly.images[i]; + } + for(uint32_t i = 0; cmd->Dispatch.read_only_group->ReadOnly.storage_buffers[i] != PULSE_NULLPTR; i++, buffer_index++) + { + PulseBuffer buffer = cmd->Dispatch.read_only_group->ReadOnly.storage_buffers[i]; + OpenGLBuffer* opengl_buffer = OPENGL_RETRIEVE_DRIVER_DATA_AS(buffer, OpenGLBuffer*); + opengl_device->glBindBufferRange(device, GL_SHADER_STORAGE_BUFFER, buffer_index, opengl_buffer->buffer, 0, buffer->size); + } + } + + if(cmd->Dispatch.read_write_group != PULSE_NULLPTR) + { + for(uint32_t i = 0; cmd->Dispatch.read_write_group->ReadWrite.images[i] != PULSE_NULLPTR; i++, image_index++) + { + PulseImage image = cmd->Dispatch.read_write_group->ReadWrite.images[i]; + } + for(uint32_t i = 0; cmd->Dispatch.read_write_group->ReadWrite.storage_buffers[i] != PULSE_NULLPTR; i++, buffer_index++) + { + PulseBuffer buffer = cmd->Dispatch.read_write_group->ReadWrite.storage_buffers[i]; + OpenGLBuffer* opengl_buffer = OPENGL_RETRIEVE_DRIVER_DATA_AS(buffer, OpenGLBuffer*); + opengl_device->glBindBufferRange(device, GL_SHADER_STORAGE_BUFFER, buffer_index, opengl_buffer->buffer, 0, buffer->size); + } + } + + if(cmd->Dispatch.uniform_group != PULSE_NULLPTR) + { + } + opengl_device->glDispatchCompute(device, cmd->Dispatch.groupcount_x, cmd->Dispatch.groupcount_y, cmd->Dispatch.groupcount_z); + + free(cmd->Dispatch.read_only_group); + free(cmd->Dispatch.read_write_group); + free(cmd->Dispatch.uniform_group); } static void OpenGLCommandsRunner(PulseCommandList cmd) diff --git a/Sources/Backends/OpenGL/OpenGLCommandList.h b/Sources/Backends/OpenGL/OpenGLCommandList.h index 92fe0f2..2e34a94 100644 --- a/Sources/Backends/OpenGL/OpenGLCommandList.h +++ b/Sources/Backends/OpenGL/OpenGLCommandList.h @@ -8,8 +8,10 @@ #define PULSE_OPENGL_COMMAND_LIST_H_ #include +#include "../../PulseInternal.h" #include "OpenGL.h" #include "OpenGLBuffer.h" +#include "OpenGLBindsGroup.h" typedef struct OpenGLCommand { @@ -42,6 +44,9 @@ typedef struct OpenGLCommand struct { + OpenGLBindsGroup* read_only_group; + OpenGLBindsGroup* read_write_group; + OpenGLBindsGroup* uniform_group; PulseComputePipeline pipeline; uint32_t groupcount_x; uint32_t groupcount_y; @@ -50,6 +55,9 @@ typedef struct OpenGLCommand struct { + OpenGLBindsGroup* read_only_group; + OpenGLBindsGroup* read_write_group; + OpenGLBindsGroup* uniform_group; PulseComputePipeline pipeline; PulseBuffer buffer; uint32_t offset; diff --git a/Sources/Backends/OpenGL/OpenGLComputePass.c b/Sources/Backends/OpenGL/OpenGLComputePass.c index c01c76b..92205a9 100644 --- a/Sources/Backends/OpenGL/OpenGLComputePass.c +++ b/Sources/Backends/OpenGL/OpenGLComputePass.c @@ -2,11 +2,15 @@ // This file is part of "Pulse" // For conditions of distribution and use, see copyright notice in LICENSE +#include + #include #include "../../PulseInternal.h" #include "OpenGL.h" +#include "OpenGLDevice.h" #include "OpenGLComputePass.h" +#include "OpenGLComputePipeline.h" PulseComputePass OpenGLCreateComputePass(PulseDevice device, PulseCommandList cmd) { @@ -37,11 +41,48 @@ PulseComputePass OpenGLBeginComputePass(PulseCommandList cmd) void OpenGLEndComputePass(PulseComputePass pass) { - PULSE_UNUSED(pass); + OpenGLComputePass* opengl_pass = OPENGL_RETRIEVE_DRIVER_DATA_AS(pass, OpenGLComputePass*); + OpenGLReturnBindsGroupToPool(opengl_pass->read_only_bind_group->pool, opengl_pass->read_only_bind_group); + OpenGLReturnBindsGroupToPool(opengl_pass->read_write_bind_group->pool, opengl_pass->read_write_bind_group); + OpenGLReturnBindsGroupToPool(opengl_pass->uniform_bind_group->pool, opengl_pass->uniform_bind_group); + opengl_pass->read_only_bind_group = PULSE_NULLPTR; + opengl_pass->read_write_bind_group = PULSE_NULLPTR; + opengl_pass->uniform_bind_group = PULSE_NULLPTR; } void OpenGLBindStorageBuffers(PulseComputePass pass, const PulseBuffer* buffers, uint32_t num_buffers) { + PulseBufferUsageFlags usage = buffers[0]->usage; + bool is_readwrite = (usage & PULSE_BUFFER_USAGE_STORAGE_WRITE) != 0; + PulseBuffer* array = is_readwrite ? pass->readwrite_storage_buffers : pass->readonly_storage_buffers; + OpenGLComputePass* opengl_pass = OPENGL_RETRIEVE_DRIVER_DATA_AS(pass, OpenGLComputePass*); + + for(uint32_t i = 0; i < num_buffers; i++) + { + if(is_readwrite && (buffers[i]->usage & PULSE_BUFFER_USAGE_STORAGE_WRITE) == 0) + { + if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(pass->cmd->device->backend)) + PulseLogError(pass->cmd->device->backend, "cannot bind a read only buffer with read-write buffers"); + PulseSetInternalError(PULSE_ERROR_INVALID_BUFFER_USAGE); + return; + } + else if(!is_readwrite && (buffers[i]->usage & PULSE_BUFFER_USAGE_STORAGE_WRITE) != 0) + { + if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(pass->cmd->device->backend)) + PulseLogError(pass->cmd->device->backend, "cannot bind a read-write buffer with read only buffers"); + PulseSetInternalError(PULSE_ERROR_INVALID_BUFFER_USAGE); + return; + } + + if(array[i] == buffers[i]) + continue; + array[i] = buffers[i]; + + if(is_readwrite) + opengl_pass->should_recreate_write_bind_group = true; + else + opengl_pass->should_recreate_read_only_bind_group = true; + } } void OpenGLBindUniformData(PulseComputePass pass, uint32_t slot, const void* data, uint32_t data_size) @@ -52,19 +93,94 @@ void OpenGLBindStorageImages(PulseComputePass pass, const PulseImage* images, ui { } +static void OpenGLBindBindsGroup(PulseComputePass pass) +{ + OpenGLComputePass* opengl_pass = OPENGL_RETRIEVE_DRIVER_DATA_AS(pass, OpenGLComputePass*); + OpenGLDevice* opengl_device = OPENGL_RETRIEVE_DRIVER_DATA_AS(pass->cmd->device, OpenGLDevice*); + OpenGLComputePipeline* opengl_pipeline = OPENGL_RETRIEVE_DRIVER_DATA_AS(pass->current_pipeline, OpenGLComputePipeline*); + + if(!opengl_pass->should_recreate_read_only_bind_group && !opengl_pass->should_recreate_write_bind_group && !opengl_pass->should_recreate_uniform_bind_group) + return; + + if(opengl_pass->should_recreate_read_only_bind_group && opengl_pipeline->readonly_group_layout != PULSE_NULLPTR) + { + if(opengl_pass->read_only_bind_group != PULSE_NULLPTR) + OpenGLReturnBindsGroupToPool(opengl_pass->read_only_bind_group->pool, opengl_pass->read_only_bind_group); + opengl_pass->read_only_bind_group = OpenGLRequestBindsGroupFromPool(OpenGLGetAvailableBindsGroupPool(&opengl_device->binds_group_pool_manager), opengl_pipeline->readonly_group_layout); + + for(uint32_t i = 0; i < pass->current_pipeline->num_readonly_storage_images; i++) + { + } + for(uint32_t i = 0; i < pass->current_pipeline->num_readonly_storage_buffers; i++) + opengl_pass->read_only_bind_group->ReadOnly.storage_buffers[i] = pass->readonly_storage_buffers[i]; + opengl_pass->should_recreate_read_only_bind_group = false; + } + if(opengl_pass->should_recreate_write_bind_group && opengl_pipeline->readwrite_group_layout != PULSE_NULLPTR) + { + if(opengl_pass->read_write_bind_group != PULSE_NULLPTR) + OpenGLReturnBindsGroupToPool(opengl_pass->read_write_bind_group->pool, opengl_pass->read_write_bind_group); + opengl_pass->read_write_bind_group = OpenGLRequestBindsGroupFromPool(OpenGLGetAvailableBindsGroupPool(&opengl_device->binds_group_pool_manager), opengl_pipeline->readwrite_group_layout); + + for(uint32_t i = 0; i < pass->current_pipeline->num_readwrite_storage_images; i++) + { + } + for(uint32_t i = 0; i < pass->current_pipeline->num_readwrite_storage_buffers; i++) + opengl_pass->read_write_bind_group->ReadWrite.storage_buffers[i] = pass->readwrite_storage_buffers[i]; + opengl_pass->should_recreate_write_bind_group = false; + } + if(opengl_pass->should_recreate_uniform_bind_group && opengl_pipeline->uniform_group_layout != PULSE_NULLPTR) + { + if(opengl_pass->uniform_bind_group != PULSE_NULLPTR) + OpenGLReturnBindsGroupToPool(opengl_pass->uniform_bind_group->pool, opengl_pass->uniform_bind_group); + opengl_pass->uniform_bind_group = OpenGLRequestBindsGroupFromPool(OpenGLGetAvailableBindsGroupPool(&opengl_device->binds_group_pool_manager), opengl_pipeline->uniform_group_layout); + + for(uint32_t i = 0; i < pass->current_pipeline->num_uniform_buffers; i++) + opengl_pass->uniform_bind_group->Uniform.buffers[i] = pass->uniform_buffers[i]; + opengl_pass->should_recreate_uniform_bind_group = false; + } +} + void OpenGLBindComputePipeline(PulseComputePass pass, PulseComputePipeline pipeline) { - PULSE_UNUSED(pass); PULSE_UNUSED(pipeline); + OpenGLComputePass* opengl_pass = OPENGL_RETRIEVE_DRIVER_DATA_AS(pass, OpenGLComputePass*); + opengl_pass->should_recreate_read_only_bind_group = true; + opengl_pass->should_recreate_write_bind_group = true; + opengl_pass->should_recreate_uniform_bind_group = true; } void OpenGLDispatchComputations(PulseComputePass pass, uint32_t groupcount_x, uint32_t groupcount_y, uint32_t groupcount_z) { + OpenGLComputePass* opengl_pass = OPENGL_RETRIEVE_DRIVER_DATA_AS(pass, OpenGLComputePass*); + OpenGLBindBindsGroup(pass); + OpenGLCommand command = { 0 }; command.type = OPENGL_COMMAND_DISPATCH; command.Dispatch.groupcount_x = groupcount_x; command.Dispatch.groupcount_y = groupcount_y; command.Dispatch.groupcount_z = groupcount_z; command.Dispatch.pipeline = pass->current_pipeline; + + if(opengl_pass->read_only_bind_group != PULSE_NULLPTR) + { + command.Dispatch.read_only_group = (OpenGLBindsGroup*)malloc(sizeof(OpenGLBindsGroup)); + PULSE_CHECK_ALLOCATION(command.Dispatch.read_only_group); + memcpy(command.Dispatch.read_only_group, opengl_pass->read_only_bind_group, sizeof(OpenGLBindsGroup)); + } + + if(opengl_pass->read_write_bind_group != PULSE_NULLPTR) + { + command.Dispatch.read_write_group = (OpenGLBindsGroup*)malloc(sizeof(OpenGLBindsGroup)); + PULSE_CHECK_ALLOCATION(command.Dispatch.read_write_group); + memcpy(command.Dispatch.read_write_group, opengl_pass->read_write_bind_group, sizeof(OpenGLBindsGroup)); + } + + if(opengl_pass->uniform_bind_group != PULSE_NULLPTR) + { + command.Dispatch.uniform_group = (OpenGLBindsGroup*)malloc(sizeof(OpenGLBindsGroup)); + PULSE_CHECK_ALLOCATION(command.Dispatch.uniform_group); + memcpy(command.Dispatch.uniform_group, opengl_pass->uniform_bind_group, sizeof(OpenGLBindsGroup)); + } + OpenGLQueueCommand(pass->cmd, command); } diff --git a/Sources/Backends/OpenGL/OpenGLComputePass.h b/Sources/Backends/OpenGL/OpenGLComputePass.h index b816232..71edcdc 100644 --- a/Sources/Backends/OpenGL/OpenGLComputePass.h +++ b/Sources/Backends/OpenGL/OpenGLComputePass.h @@ -11,10 +11,17 @@ #include "OpenGL.h" #include "OpenGLBuffer.h" #include "OpenGLCommandList.h" +#include "OpenGLBindsGroup.h" typedef struct OpenGLComputePass { - int dummy; + OpenGLBindsGroup* read_only_bind_group; + OpenGLBindsGroup* read_write_bind_group; + OpenGLBindsGroup* uniform_bind_group; + + bool should_recreate_read_only_bind_group; + bool should_recreate_write_bind_group; + bool should_recreate_uniform_bind_group; } OpenGLComputePass; PulseComputePass OpenGLCreateComputePass(PulseDevice device, PulseCommandList cmd); diff --git a/Sources/Backends/OpenGL/OpenGLComputePipeline.c b/Sources/Backends/OpenGL/OpenGLComputePipeline.c index 56be2b5..67c2819 100644 --- a/Sources/Backends/OpenGL/OpenGLComputePipeline.c +++ b/Sources/Backends/OpenGL/OpenGLComputePipeline.c @@ -6,8 +6,9 @@ #include "../../PulseInternal.h" #include "OpenGL.h" -#include "OpenGLComputePipeline.h" #include "OpenGLDevice.h" +#include "OpenGLBindsGroup.h" +#include "OpenGLComputePipeline.h" PulseComputePipeline OpenGLCreateComputePipeline(PulseDevice device, const PulseComputePipelineCreateInfo* info) { @@ -32,6 +33,33 @@ PulseComputePipeline OpenGLCreateComputePipeline(PulseDevice device, const Pulse } opengl_pipeline->program = opengl_device->glCreateShaderProgramv(device, GL_COMPUTE_SHADER, 1, (const GLchar**)(&info->code)); + GLint linked = GL_FALSE; + opengl_device->glGetProgramiv(device, opengl_pipeline->program, GL_LINK_STATUS, &linked); + if(linked != GL_TRUE) + { + if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend)) + { + GLint len = 0; + opengl_device->glGetProgramiv(device, opengl_pipeline->program, GL_INFO_LOG_LENGTH, &len); + + char* log = (char*)malloc(len); + PULSE_CHECK_ALLOCATION_RETVAL(log, PULSE_NULL_HANDLE); + opengl_device->glGetProgramInfoLog(device, opengl_pipeline->program, len, PULSE_NULLPTR, log); + + PulseLogErrorFmt(device->backend, "compute pipeline could not be created\n%.*s", len, log); + + free(log); + } + + opengl_device->glDeleteProgram(device, opengl_pipeline->program); + free(opengl_pipeline); + free(pipeline); + return PULSE_NULL_HANDLE; + } + + opengl_pipeline->readonly_group_layout = OpenGLGetBindsGroupLayout(&opengl_device->binds_group_layout_manager, info->num_readonly_storage_images, info->num_readonly_storage_buffers, 0, 0, 0); + opengl_pipeline->readwrite_group_layout = OpenGLGetBindsGroupLayout(&opengl_device->binds_group_layout_manager, 0, 0, info->num_readwrite_storage_images, info->num_readwrite_storage_buffers, 0); + opengl_pipeline->uniform_group_layout = OpenGLGetBindsGroupLayout(&opengl_device->binds_group_layout_manager, 0, 0, 0, 0, info->num_uniform_buffers); if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(device->backend)) PulseLogInfoFmt(device->backend, "%s created new compute pipeline %p", device->backend->backend == PULSE_BACKEND_OPENGL ? "(OpenGL)" : "(OpenGL ES)", pipeline); @@ -47,8 +75,9 @@ void OpenGLDestroyComputePipeline(PulseDevice device, PulseComputePipeline pipel return; } - PULSE_UNUSED(device); + OpenGLDevice* opengl_device = OPENGL_RETRIEVE_DRIVER_DATA_AS(device, OpenGLDevice*); OpenGLComputePipeline* opengl_pipeline = OPENGL_RETRIEVE_DRIVER_DATA_AS(pipeline, OpenGLComputePipeline*); + opengl_device->glDeleteProgram(device, opengl_pipeline->program); free(opengl_pipeline); if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(device->backend)) diff --git a/Sources/Backends/OpenGL/OpenGLComputePipeline.h b/Sources/Backends/OpenGL/OpenGLComputePipeline.h index a97d478..f9acb9d 100644 --- a/Sources/Backends/OpenGL/OpenGLComputePipeline.h +++ b/Sources/Backends/OpenGL/OpenGLComputePipeline.h @@ -9,10 +9,14 @@ #include #include "OpenGL.h" +#include "OpenGLBindsGroup.h" typedef struct OpenGLComputePipeline { GLuint program; + OpenGLBindsGroupLayout* readonly_group_layout; + OpenGLBindsGroupLayout* readwrite_group_layout; + OpenGLBindsGroupLayout* uniform_group_layout; } OpenGLComputePipeline; PulseComputePipeline OpenGLCreateComputePipeline(PulseDevice device, const PulseComputePipelineCreateInfo* info); diff --git a/Sources/Backends/OpenGL/OpenGLDevice.c b/Sources/Backends/OpenGL/OpenGLDevice.c index 6e424b5..df03627 100644 --- a/Sources/Backends/OpenGL/OpenGLDevice.c +++ b/Sources/Backends/OpenGL/OpenGLDevice.c @@ -47,6 +47,10 @@ const char* OpenGLVerbaliseError(GLenum code) static void OpenGLDebugMessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* user_param) { + PULSE_UNUSED(source); + PULSE_UNUSED(type); + PULSE_UNUSED(id); + PULSE_UNUSED(severity); PulseDevice device = (PulseDevice)user_param; PulseLogInfoFmt(device->backend, "%s debug message catched: %.*s", device->backend->backend == PULSE_BACKEND_OPENGL ? "(OpenGL)" : "(OpenGL ES)", length, message); } @@ -246,7 +250,7 @@ PulseDevice OpenGLCreateDevice(PulseBackend backend, PulseDevice* forbiden_devic return PULSE_NULL_HANDLE; } - if(backend->debug_level != PULSE_NO_DEBUG && device->original_function_ptrs[glDebugMessageCallback] != PULSE_NULLPTR) + if(backend->debug_level > PULSE_LOW_DEBUG && device->original_function_ptrs[glDebugMessageCallback] != PULSE_NULLPTR) { device->glEnable(pulse_device, GL_DEBUG_OUTPUT); //device->glEnable(pulse_device, GL_DEBUG_OUTPUT_SYNCHRONOUS); @@ -261,6 +265,9 @@ PulseDevice OpenGLCreateDevice(PulseBackend backend, PulseDevice* forbiden_devic for(uint32_t i = 0; i < device->supported_extensions_count; i++) device->device_id = PulseHashCombine(device->device_id, PulseHashString(device->supported_extensions[i])); + OpenGLInitBindsGroupPoolManager(&device->binds_group_pool_manager, pulse_device); + OpenGLInitBindsGroupLayoutManager(&device->binds_group_layout_manager, pulse_device); + if(PULSE_IS_BACKEND_HIGH_LEVEL_DEBUG(backend)) PulseLogInfoFmt(backend, "%s created device from %s", backend->backend == PULSE_BACKEND_OPENGL ? "(OpenGL)" : "(OpenGL ES)", device->glGetString(pulse_device, GL_RENDERER)); return pulse_device; @@ -282,6 +289,8 @@ void OpenGLDestroyDevice(PulseDevice device) if(device == PULSE_NULL_HANDLE || device->driver_data == PULSE_NULLPTR) return; OpenGLDevice* opengl_device = OPENGL_RETRIEVE_DRIVER_DATA_AS(device, OpenGLDevice*); + OpenGLDestroyBindsGroupPoolManager(&opengl_device->binds_group_pool_manager); + OpenGLDestroyBindsGroupLayoutManager(&opengl_device->binds_group_layout_manager); #ifdef PULSE_PLAT_WINDOWS if(opengl_device->context_type == OPENGL_CONTEXT_WGL) {} // TODO: WGL diff --git a/Sources/Backends/OpenGL/OpenGLDevice.h b/Sources/Backends/OpenGL/OpenGLDevice.h index f53508c..38e41fa 100644 --- a/Sources/Backends/OpenGL/OpenGLDevice.h +++ b/Sources/Backends/OpenGL/OpenGLDevice.h @@ -9,6 +9,7 @@ #include #include "OpenGL.h" +#include "OpenGLBindsGroup.h" #include "EGL/EGLInstance.h" #define PULSE_OPENGL_WRAPPER_RET(ret, fn, arg_list, param_list, cast) typedef ret (*PulseOpenGLWrapperPFN_##fn) arg_list ; @@ -27,6 +28,9 @@ typedef struct OpenGLDevice }; OpenGLContextType context_type; + OpenGLBindsGroupPoolManager binds_group_pool_manager; + OpenGLBindsGroupLayoutManager binds_group_layout_manager; + #define PULSE_OPENGL_WRAPPER_RET(ret, fn, arg_list, param_list, cast) PulseOpenGLWrapperPFN_##fn fn; #define PULSE_OPENGL_WRAPPER(fn, arg_list, param_list, cast) PulseOpenGLWrapperPFN_##fn fn; #include "OpenGLWraps.h" diff --git a/Sources/Backends/OpenGL/OpenGLEnums.h b/Sources/Backends/OpenGL/OpenGLEnums.h index 3d50d24..eb835fc 100644 --- a/Sources/Backends/OpenGL/OpenGLEnums.h +++ b/Sources/Backends/OpenGL/OpenGLEnums.h @@ -54,6 +54,15 @@ typedef enum OpenGLCommandType OPENGL_COMMAND_END_ENUM } OpenGLCommandType; +typedef enum OpenGLBindsGroupType +{ + OPENGL_BINDS_GROUP_READ_ONLY, + OPENGL_BINDS_GROUP_READ_WRITE, + OPENGL_BINDS_GROUP_UNIFORM, + + OPENGL_BINDS_GROUP_END_ENUM +} OpenGLBindsGroupType; + #endif // PULSE_OPENGL_ENUMS_H_ #endif // PULSE_ENABLE_OPENGL_BACKEND diff --git a/Sources/Backends/Vulkan/VulkanDescriptor.c b/Sources/Backends/Vulkan/VulkanDescriptor.c index 52fedda..2e06e23 100644 --- a/Sources/Backends/Vulkan/VulkanDescriptor.c +++ b/Sources/Backends/Vulkan/VulkanDescriptor.c @@ -207,7 +207,7 @@ VulkanDescriptorSet* VulkanRequestDescriptorSetFromPool(VulkanDescriptorSetPool* VulkanDescriptorSet* set = pool->free_sets[i]; PULSE_DEFRAG_ARRAY(pool->free_sets, VULKAN_POOL_SIZE, i); pool->free_index--; - pool->used_sets[pool->used_index] = (VulkanDescriptorSet*)set; + pool->used_sets[pool->used_index] = set; pool->used_index++; return set; } @@ -229,6 +229,9 @@ VulkanDescriptorSet* VulkanRequestDescriptorSetFromPool(VulkanDescriptorSetPool* alloc_info.pSetLayouts = &layout->layout; CHECK_VK_RETVAL(pool->device->backend, vulkan_device->vkAllocateDescriptorSets(vulkan_device->device, &alloc_info, &set->set), PULSE_ERROR_INITIALIZATION_FAILED, PULSE_NULLPTR); + pool->used_sets[pool->used_index] = set; + pool->used_index++; + pool->allocations_count++; return set; }