This commit is contained in:
2025-03-24 17:41:51 +01:00
parent d7679857aa
commit bd0c564566
18 changed files with 310 additions and 33 deletions

View File

@@ -166,6 +166,7 @@ bool EGLLoadInstance(EGLInstance* instance, PulseDevice* forbiden_devices, uint3
uint32_t device_id = PulseHashString((const char*)glGetString(GL_VENDOR));
device_id = PulseHashCombine(device_id, PulseHashString((const char*)glGetString(GL_RENDERER)));
GLint gl_extension_count = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &gl_extension_count);
for(int i = 0; i < gl_extension_count; i++)
device_id = PulseHashCombine(device_id, PulseHashString((const char*)glGetStringi(GL_EXTENSIONS, i)));

View File

@@ -14,10 +14,7 @@
#include "OpenGLEnums.h"
#define GL_GLES_PROTOTYPES 0
#include <GLES3/gl31.h>
#define GL_STACK_UNDERFLOW 0x0504
#define GL_STACK_OVERFLOW 0x0503
#include <GLES3/gl32.h>
typedef void(*GLFunction)(void);

View File

@@ -26,7 +26,14 @@ PulseBuffer OpenGLCreateBuffer(PulseDevice device, const PulseBufferCreateInfo*
buffer->size = create_infos->size;
buffer->usage = create_infos->usage;
void* data = calloc(1, create_infos->size);
PULSE_CHECK_ALLOCATION_RETVAL(data, PULSE_NULL_HANDLE);
opengl_device->glGenBuffers(device, 1, &opengl_buffer->buffer);
opengl_device->glBindBuffer(device, GL_SHADER_STORAGE_BUFFER, opengl_buffer->buffer);
opengl_device->glBufferData(device, GL_SHADER_STORAGE_BUFFER, create_infos->size, data, GL_DYNAMIC_COPY);
free(data);
return buffer;
}

View File

@@ -7,6 +7,34 @@
#include "../../PulseInternal.h"
#include "OpenGL.h"
#include "OpenGLCommandList.h"
#include "OpenGLDevice.h"
#include "OpenGLBuffer.h"
#include "OpenGLFence.h"
#include "OpenGLComputePass.h"
static void OpenGLCommandCopyBufferToBuffer(PulseDevice device, OpenGLCommand* cmd)
{
const PulseBufferRegion* src = cmd->CopyBufferToBuffer.src;
const PulseBufferRegion* dst = cmd->CopyBufferToBuffer.dst;
OpenGLBuffer* src_buffer = OPENGL_RETRIEVE_DRIVER_DATA_AS(src->buffer, OpenGLBuffer*);
OpenGLBuffer* dst_buffer = OPENGL_RETRIEVE_DRIVER_DATA_AS(dst->buffer, OpenGLBuffer*);
OpenGLDevice* opengl_device = OPENGL_RETRIEVE_DRIVER_DATA_AS(device, OpenGLDevice*);
opengl_device->glBindBuffer(device, GL_COPY_READ_BUFFER, src_buffer->buffer);
opengl_device->glBindBuffer(device, GL_COPY_WRITE_BUFFER, dst_buffer->buffer);
opengl_device->glCopyBufferSubData(device, GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, src->offset, dst->offset, src->size);
free((void*)src);
free((void*)dst);
}
static void OpenGLCommandDispatch(PulseDevice device, OpenGLCommand* cmd)
{
OpenGLDevice* opengl_device = OPENGL_RETRIEVE_DRIVER_DATA_AS(device, OpenGLDevice*);
opengl_device->glDispatchCompute(device, cmd->Dispatch.groupcount_x, cmd->Dispatch.groupcount_y, cmd->Dispatch.groupcount_z);
}
static void OpenGLCommandsRunner(PulseCommandList cmd)
{
@@ -20,26 +48,40 @@ static void OpenGLCommandsRunner(PulseCommandList cmd)
OpenGLCommand* command = &opengl_cmd->commands[i];
switch(command->type)
{
case OPENGL_COMMAND_COPY_BUFFER_TO_BUFFER: OpenGLCommandCopyBufferToBuffer(command); break;
case OPENGL_COMMAND_COPY_BUFFER_TO_BUFFER: OpenGLCommandCopyBufferToBuffer(cmd->device, command); break;
case OPENGL_COMMAND_COPY_BUFFER_TO_IMAGE: break;
case OPENGL_COMMAND_COPY_IMAGE_TO_BUFFER: break;
case OPENGL_COMMAND_DISPATCH: OpenGLCommandDispatch(command); break;
case OPENGL_COMMAND_DISPATCH: OpenGLCommandDispatch(cmd->device, command); break;
case OPENGL_COMMAND_DISPATCH_INDIRECT: break;
default: break;
}
}
if(opengl_cmd->fence != PULSE_NULL_HANDLE)
{
OpenGLFence* fence = OPENGL_RETRIEVE_DRIVER_DATA_AS(opengl_cmd->fence, OpenGLFence*);
atomic_store(&fence->signal, true);
}
cmd->state = PULSE_COMMAND_LIST_STATE_READY;
}
PulseCommandList OpenGLRequestCommandList(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);
OpenGLCommandList* opengl_cmd = (OpenGLCommandList*)calloc(1, sizeof(OpenGLCommandList));
PULSE_CHECK_ALLOCATION_RETVAL(opengl_cmd, PULSE_NULL_HANDLE);
cmd->usage = usage;
cmd->device = device;
cmd->driver_data = opengl_cmd;
cmd->thread_id = PulseGetThreadID();
cmd->pass = OpenGLCreateComputePass(device, cmd);
cmd->state = PULSE_COMMAND_LIST_STATE_RECORDING;
cmd->is_available = false;
return cmd;
}
void OpenGLQueueCommand(PulseCommandList cmd, OpenGLCommand command)
@@ -52,8 +94,17 @@ void OpenGLQueueCommand(PulseCommandList cmd, OpenGLCommand command)
bool OpenGLSubmitCommandList(PulseDevice device, PulseCommandList cmd, PulseFence fence)
{
PULSE_UNUSED(device);
cmd->state = PULSE_COMMAND_LIST_STATE_SENT;
if(fence != PULSE_NULL_HANDLE)
fence->cmd = cmd;
OpenGLCommandsRunner(cmd);
return true;
}
void OpenGLReleaseCommandList(PulseDevice device, PulseCommandList cmd)
{
OpenGLDestroyComputePass(device, cmd->pass);
free(cmd->driver_data);
free(cmd);
}

View File

@@ -10,18 +10,34 @@
PulseComputePass OpenGLCreateComputePass(PulseDevice device, PulseCommandList cmd)
{
PULSE_UNUSED(device);
PulseComputePass pass = (PulseComputePass)calloc(1, sizeof(PulseComputePassHandler));
PULSE_CHECK_ALLOCATION_RETVAL(pass, PULSE_NULL_HANDLE);
OpenGLComputePass* opengl_pass = (OpenGLComputePass*)calloc(1, sizeof(OpenGLComputePass));
PULSE_CHECK_ALLOCATION_RETVAL(opengl_pass, PULSE_NULL_HANDLE);
pass->cmd = cmd;
pass->driver_data = opengl_pass;
return pass;
}
void OpenGLDestroyComputePass(PulseDevice device, PulseComputePass pass)
{
PULSE_UNUSED(device);
free(pass->driver_data);
free(pass);
}
PulseComputePass OpenGLBeginComputePass(PulseCommandList cmd)
{
return cmd->pass;
}
void OpenGLEndComputePass(PulseComputePass pass)
{
PULSE_UNUSED(pass);
}
void OpenGLBindStorageBuffers(PulseComputePass pass, const PulseBuffer* buffers, uint32_t num_buffers)
@@ -38,8 +54,17 @@ void OpenGLBindStorageImages(PulseComputePass pass, const PulseImage* images, ui
void OpenGLBindComputePipeline(PulseComputePass pass, PulseComputePipeline pipeline)
{
PULSE_UNUSED(pass);
PULSE_UNUSED(pipeline);
}
void OpenGLDispatchComputations(PulseComputePass pass, uint32_t groupcount_x, uint32_t groupcount_y, uint32_t groupcount_z)
{
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;
OpenGLQueueCommand(pass->cmd, command);
}

View File

@@ -14,6 +14,7 @@
typedef struct OpenGLComputePass
{
int dummy;
} OpenGLComputePass;
PulseComputePass OpenGLCreateComputePass(PulseDevice device, PulseCommandList cmd);

View File

@@ -12,6 +12,7 @@
typedef struct OpenGLComputePipeline
{
int dummy;
} OpenGLComputePipeline;
PulseComputePipeline OpenGLCreateComputePipeline(PulseDevice device, const PulseComputePipelineCreateInfo* info);

View File

@@ -46,6 +46,12 @@ const char* OpenGLVerbaliseError(GLenum code)
return "unknown OpenGL error";
}
static void OpenGLDebugMessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* user_param)
{
PulseDevice device = (PulseDevice)user_param;
PulseLogInfoFmt(device->backend, "%s debug message catched: %.*s", device->backend->backend == PULSE_BACKEND_OPENGL ? "(OpenGL)" : "(OpenGL ES)", length, message);
}
static void PulseCheckGLError(PulseDevice device, const char* function)
{
OpenGLDevice* opengl_device = OPENGL_RETRIEVE_DRIVER_DATA_AS(device, OpenGLDevice*);
@@ -108,6 +114,26 @@ static void OpenGLDeviceMakeCurrent(PulseDevice device)
#undef PULSE_OPENGL_WRAPPER
#undef PULSE_OPENGL_WRAPPER_RET
static bool OpenGLLoadFallbackFunction(PulseDevice device, OpenGLFunctionIndex index, GLFunctionLoad load)
{
OpenGLDevice* opengl_device = OPENGL_RETRIEVE_DRIVER_DATA_AS(device, OpenGLDevice*);
if(index == glDebugMessageCallback)
{
GLFunction fn = PULSE_NULLPTR;
if(OpenGLDeviceSupportsExtension(device, "GL_KHR_debug"))
fn = load("glDebugMessageCallbackKHR");
if(!fn && device->backend->backend == PULSE_BACKEND_OPENGL && OpenGLDeviceSupportsExtension(device, "GL_ARB_debug_output"))
fn = load("glDebugMessageCallbackARB");
if(fn)
opengl_device->original_function_ptrs[index] = fn;
}
return opengl_device->original_function_ptrs[index] != PULSE_NULLPTR;
}
static bool OpenGLLoadFunction(PulseDevice device, OpenGLFunctionIndex index)
{
OpenGLDevice* opengl_device = OPENGL_RETRIEVE_DRIVER_DATA_AS(device, OpenGLDevice*);
@@ -123,7 +149,7 @@ static bool OpenGLLoadFunction(PulseDevice device, OpenGLFunctionIndex index)
#endif
GLFunction fn = load(OpenGLFunctionIndexToFunctionName[index]);
if(!fn)
if(!fn && index > OPENGL_FUNCTION_INDEX_START_ENUM && !OpenGLLoadFallbackFunction(device, index, load))
{
PulseSetInternalError(PULSE_ERROR_INITIALIZATION_FAILED);
return false;
@@ -132,11 +158,11 @@ static bool OpenGLLoadFunction(PulseDevice device, OpenGLFunctionIndex index)
return true;
}
static bool OpenGLLoadFunctions(PulseDevice device)
static bool OpenGLLoadCoreFunctions(PulseDevice device)
{
OpenGLDevice* opengl_device = OPENGL_RETRIEVE_DRIVER_DATA_AS(device, OpenGLDevice*);
for(int i = 0; i < OPENGL_FUNCTION_INDEX_END_ENUM; i++)
for(int i = 0; i < OPENGL_CORE_FUNCTION_INDEX_END_ENUM; i++)
{
if(!OpenGLLoadFunction(device, i))
return false;
@@ -149,6 +175,27 @@ static bool OpenGLLoadFunctions(PulseDevice device)
return true;
}
static bool OpenGLLoadFunctions(PulseDevice device)
{
OpenGLDevice* opengl_device = OPENGL_RETRIEVE_DRIVER_DATA_AS(device, OpenGLDevice*);
for(int i = OPENGL_CORE_FUNCTION_INDEX_END_ENUM; i < OPENGL_FUNCTION_INDEX_END_ENUM; i++)
{
if(!OpenGLLoadFunction(device, i))
return false;
}
#undef PULSE_OPENGL_GL_GLES_FUNCTION
#define PULSE_OPENGL_FUNCTION(fn, T)
#define PULSE_OPENGL_GL_GLES_FUNCTION(glver, glesver,fn, T) opengl_device->fn = PulseOpenGLWrapper_##fn;
#include "OpenGLFunctions.h"
#undef PULSE_OPENGL_FUNCTION
#undef PULSE_OPENGL_GL_GLES_FUNCTION
return true;
}
PulseDevice OpenGLCreateDevice(PulseBackend backend, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count)
{
PULSE_CHECK_HANDLE_RETVAL(backend, PULSE_NULLPTR);
@@ -179,6 +226,20 @@ PulseDevice OpenGLCreateDevice(PulseBackend backend, PulseDevice* forbiden_devic
device->context_type = OPENGL_CONTEXT_EGL;
#endif
if(!OpenGLLoadCoreFunctions(pulse_device))
{
EGLUnloadInstance(&device->egl_instance);
PulseSetInternalError(PULSE_ERROR_INITIALIZATION_FAILED);
return PULSE_NULL_HANDLE;
}
GLint gl_extension_count = 0;
device->glGetIntegerv(pulse_device, GL_NUM_EXTENSIONS, &gl_extension_count);
device->supported_extensions_count = gl_extension_count;
device->supported_extensions = (const char**)calloc(device->supported_extensions_count, sizeof(const char*));
for(uint32_t i = 0; i < device->supported_extensions_count; i++)
device->supported_extensions[i] = (const char*)device->glGetStringi(pulse_device, GL_EXTENSIONS, i);
if(!OpenGLLoadFunctions(pulse_device))
{
EGLUnloadInstance(&device->egl_instance);
@@ -186,25 +247,48 @@ 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)
{
device->glDebugMessageCallback(pulse_device, OpenGLDebugMessageCallback, pulse_device);
if(backend->debug_level >= PULSE_LOW_DEBUG)
device->glDebugMessageControl(pulse_device, GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, 0, PULSE_NULLPTR, GL_FALSE);
if(backend->debug_level >= PULSE_HIGH_DEBUG)
{
device->glDebugMessageControl(pulse_device, GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, PULSE_NULLPTR, GL_FALSE);
device->glDebugMessageControl(pulse_device, GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, PULSE_NULLPTR, GL_FALSE);
device->glDebugMessageControl(pulse_device, GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, PULSE_NULLPTR, GL_FALSE);
//device->glDebugMessageControl(pulse_device, GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, PULSE_NULLPTR, GL_FALSE);
}
}
PULSE_LOAD_DRIVER_DEVICE(OpenGL);
device->device_id = PulseHashString((const char*)device->glGetString(pulse_device, GL_VENDOR));
device->device_id = PulseHashCombine(device->device_id, PulseHashString((const char*)device->glGetString(pulse_device, GL_RENDERER)));
GLint gl_extension_count = 0;
for(int i = 0; i < gl_extension_count; i++)
device->device_id = PulseHashCombine(device->device_id, PulseHashString((const char*)device->glGetStringi(pulse_device, GL_EXTENSIONS, i)));
for(uint32_t i = 0; i < device->supported_extensions_count; i++)
device->device_id = PulseHashCombine(device->device_id, PulseHashString(device->supported_extensions[i]));
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;
}
void OpenGLDestroyDevice(PulseDevice device)
bool OpenGLDeviceSupportsExtension(PulseDevice device, const char* name)
{
OpenGLDevice* opengl_device = OPENGL_RETRIEVE_DRIVER_DATA_AS(device, OpenGLDevice*);
if(opengl_device == PULSE_NULLPTR)
return;
for(uint32_t i = 0; i < opengl_device->supported_extensions_count; i++)
{
if(strcmp(opengl_device->supported_extensions[i], name) == 0)
return true;
}
return false;
}
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*);
#ifdef PULSE_PLAT_WINDOWS
if(opengl_device->context_type == OPENGL_CONTEXT_WGL)
{} // TODO: WGL

View File

@@ -33,10 +33,14 @@ typedef struct OpenGLDevice
#undef PULSE_OPENGL_WRAPPER
#undef PULSE_OPENGL_WRAPPER_RET
const char** supported_extensions;
uint32_t supported_extensions_count;
uint32_t device_id;
} OpenGLDevice;
PulseDevice OpenGLCreateDevice(PulseBackend backend, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count);
bool OpenGLDeviceSupportsExtension(PulseDevice device, const char* name);
void OpenGLDestroyDevice(PulseDevice device);
#endif // PULSE_OPENGL_DEVICE_H_

View File

@@ -15,11 +15,28 @@ typedef enum OpenGLContextType
OPENGL_CONTEXT_END_ENUM
} OpenGLContextType;
typedef enum OpenGLFunctionIndex
typedef enum OpenGLCoreFunctionIndex
{
#undef PULSE_OPENGL_GL_GLES_FUNCTION
#define PULSE_OPENGL_GL_GLES_FUNCTION(glver, glesver, fn, T)
#define PULSE_OPENGL_FUNCTION(fn, T) fn,
#include "OpenGLFunctions.h"
#undef PULSE_OPENGL_FUNCTION
#undef PULSE_OPENGL_GL_GLES_FUNCTION
OPENGL_CORE_FUNCTION_INDEX_END_ENUM
} OpenGLCoreFunctionIndex;
typedef enum OpenGLFunctionIndex
{
OPENGL_FUNCTION_INDEX_START_ENUM = OPENGL_CORE_FUNCTION_INDEX_END_ENUM - 1,
#undef PULSE_OPENGL_GL_GLES_FUNCTION
#define PULSE_OPENGL_GL_GLES_FUNCTION(glver, glesver, fn, T) fn,
#define PULSE_OPENGL_FUNCTION(fn, T)
#include "OpenGLFunctions.h"
#undef PULSE_OPENGL_FUNCTION
#undef PULSE_OPENGL_GL_GLES_FUNCTION
OPENGL_FUNCTION_INDEX_END_ENUM
} OpenGLFunctionIndex;

View File

@@ -7,19 +7,35 @@
#include "../../PulseInternal.h"
#include "OpenGL.h"
#include "OpenGLFence.h"
#include "OpenGLDevice.h"
PulseFence OpenGLCreateFence(PulseDevice device)
{
PULSE_UNUSED(device);
PulseFence fence = (PulseFence)calloc(1, sizeof(PulseFence));
PULSE_CHECK_ALLOCATION_RETVAL(fence, PULSE_NULL_HANDLE);
return fence;
}
void OpenGLDestroyFence(PulseDevice device, PulseFence fence)
{
PULSE_UNUSED(device);
free(fence);
}
bool OpenGLIsFenceReady(PulseDevice device, PulseFence fence)
{
PULSE_UNUSED(device);
PULSE_UNUSED(fence);
return true;
}
bool OpenGLWaitForFences(PulseDevice device, const PulseFence* fences, uint32_t fences_count, bool wait_for_all)
{
PULSE_UNUSED(fences);
PULSE_UNUSED(fences_count);
PULSE_UNUSED(wait_for_all);
OpenGLDevice* opengl_device = OPENGL_RETRIEVE_DRIVER_DATA_AS(device, OpenGLDevice*);
opengl_device->glFinish(device);
return true;
}

View File

@@ -10,10 +10,6 @@
#include <Pulse.h>
#include "OpenGL.h"
typedef struct OpenGLFence
{
} OpenGLFence;
PulseFence OpenGLCreateFence(PulseDevice device);
void OpenGLDestroyFence(PulseDevice device, PulseFence fence);
bool OpenGLIsFenceReady(PulseDevice device, PulseFence fence);

View File

@@ -8,10 +8,6 @@
#error "You must define PULSE_OPENGL_FUNCTION before including this file"
#endif
#ifndef PULSE_OPENGL_GL_FUNCTION
#define PULSE_OPENGL_GL_FUNCTION(ver, name, sig) PULSE_OPENGL_FUNCTION(name, sig)
#endif
#ifndef PULSE_OPENGL_GL_GLES_FUNCTION
#define PULSE_OPENGL_GL_GLES_FUNCTION(glVer, glesVer, name, sig) PULSE_OPENGL_FUNCTION(name, sig)
#endif
@@ -140,3 +136,8 @@ PULSE_OPENGL_GL_GLES_FUNCTION(430, 310, glGetProgramResourceiv, PFNGLGETPROGRAMR
PULSE_OPENGL_GL_GLES_FUNCTION(430, 310, glGetProgramResourceIndex, PFNGLGETPROGRAMRESOURCEINDEXPROC)
PULSE_OPENGL_GL_GLES_FUNCTION(430, 310, glGetProgramResourceLocation, PFNGLGETPROGRAMRESOURCELOCATIONPROC)
PULSE_OPENGL_GL_GLES_FUNCTION(430, 310, glGetProgramResourceName, PFNGLGETPROGRAMRESOURCENAMEPROC)
// OpenGL 4.3 - OpenGL ES 3.2
PULSE_OPENGL_GL_GLES_FUNCTION(430, 320, glDebugMessageCallback, PFNGLDEBUGMESSAGECALLBACKPROC)
PULSE_OPENGL_GL_GLES_FUNCTION(430, 320, glDebugMessageControl, PFNGLDEBUGMESSAGECONTROLPROC)
PULSE_OPENGL_GL_GLES_FUNCTION(430, 320, glDispatchComputeIndirect, PFNGLDISPATCHCOMPUTEINDIRECTPROC)

View File

@@ -12,6 +12,7 @@
typedef struct OpenGLImage
{
int dummy;
} OpenGLImage;
PulseImage OpenGLCreateImage(PulseDevice device, const PulseImageCreateInfo* create_infos);

View File

@@ -124,6 +124,7 @@ PULSE_OPENGL_WRAPPER(glProgramParameteri, (PulseDevice device, GLuint program, G
PULSE_OPENGL_WRAPPER(glTexStorage2D, (PulseDevice device, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height), (target, levels, internalformat, width, height), PFNGLTEXSTORAGE2DPROC)
PULSE_OPENGL_WRAPPER(glTexStorage3D, (PulseDevice device, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth), (target, levels, internalformat, width, height, depth), PFNGLTEXSTORAGE3DPROC)
PULSE_OPENGL_WRAPPER(glDispatchCompute, (PulseDevice device, GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z), (num_groups_x, num_groups_y, num_groups_z), PFNGLDISPATCHCOMPUTEPROC)
PULSE_OPENGL_WRAPPER(glDispatchComputeIndirect, (PulseDevice device, GLintptr indirect), (indirect), PFNGLDISPATCHCOMPUTEINDIRECTPROC)
PULSE_OPENGL_WRAPPER(glGetProgramInterfaceiv, (PulseDevice device, GLuint program, GLenum programInterface, GLenum pname, GLint *params), (program, programInterface, pname, params), PFNGLGETPROGRAMINTERFACEIVPROC)
PULSE_OPENGL_WRAPPER_RET(GLuint, glGetProgramResourceIndex, (PulseDevice device, GLuint program, GLenum programInterface, const GLchar *name), (program, programInterface, name), PFNGLGETPROGRAMRESOURCEINDEXPROC)
PULSE_OPENGL_WRAPPER(glGetProgramResourceName, (PulseDevice device, GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name), (program, programInterface, index, bufSize, length, name), PFNGLGETPROGRAMRESOURCENAMEPROC)
@@ -133,3 +134,5 @@ PULSE_OPENGL_WRAPPER(glBindImageTexture, (PulseDevice device, GLuint unit, GLuin
PULSE_OPENGL_WRAPPER(glGetBooleani_v, (PulseDevice device, GLenum target, GLuint index, GLboolean *data), (target, index, data), PFNGLGETBOOLEANI_VPROC)
PULSE_OPENGL_WRAPPER(glMemoryBarrier, (PulseDevice device, GLbitfield barriers), (barriers), PFNGLMEMORYBARRIERPROC)
PULSE_OPENGL_WRAPPER(glMemoryBarrierByRegion, (PulseDevice device, GLbitfield barriers), (barriers), PFNGLMEMORYBARRIERBYREGIONPROC)
PULSE_OPENGL_WRAPPER(glDebugMessageControl, (PulseDevice device, GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled), (source, type, severity, count, ids, enabled), PFNGLDEBUGMESSAGECONTROLPROC)
PULSE_OPENGL_WRAPPER(glDebugMessageCallback, (PulseDevice device, GLDEBUGPROC callback, const void *userParam), (callback, userParam), PFNGLDEBUGMESSAGECALLBACKPROC)