This commit is contained in:
2025-04-07 18:13:55 +02:00
parent 9e8084fcf3
commit c99d32f43e
16 changed files with 407 additions and 11 deletions

View File

@@ -119,7 +119,7 @@ bool EGLLoadOpenGLContext(EGLInstance* instance, EGLDisplay* display, EGLDeviceE
return true;
}
bool EGLLoadInstance(EGLInstance* instance, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count, bool es_context)
bool EGLLoadInstance(EGLInstance* instance, const char** extensions, uint32_t extensions_count, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count, bool es_context)
{
PULSE_CHECK_PTR_RETVAL(instance, false);
@@ -161,14 +161,25 @@ bool EGLLoadInstance(EGLInstance* instance, PulseDevice* forbiden_devices, uint3
continue;
}
// Check for forbiden devices
uint32_t extensions_found_count = 0;
{
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)));
{
const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
device_id = PulseHashCombine(device_id, PulseHashString(extension));
for(uint32_t j = 0; j < extensions_count; j++) // Not optimal
{
if(strcmp(extensions[j], extension) == 0)
{
extensions_found_count++;
break;
}
}
}
for(uint32_t j = 0; j < forbiden_devices_count; j++)
{
@@ -211,12 +222,17 @@ bool EGLLoadInstance(EGLInstance* instance, PulseDevice* forbiden_devices, uint3
instance->eglDestroyContext(display, context);
instance->eglTerminate(display);
if(extensions_found_count != extensions_count)
current_device_score = 0;
if(current_device_score > best_device_score)
{
best_device_score = current_device_score;
instance->device = devices[i];
}
}
if(instance->device == EGL_NO_DEVICE_EXT)
return false;
}
return EGLLoadOpenGLContext(instance, &instance->display, instance->device, &instance->config, &instance->surface, &instance->context, es_context);

View File

@@ -28,7 +28,7 @@ typedef struct EGLInstance
#undef PULSE_EGL_FUNCTION_EXT
} EGLInstance;
bool EGLLoadInstance(EGLInstance* instance, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count, bool es_context);
bool EGLLoadInstance(EGLInstance* instance, const char** extensions, uint32_t extensions_count, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count, bool es_context);
void EGLUnloadInstance(EGLInstance* instance);
#endif // PULSE_EGL_CONTEXT_H_

View File

@@ -16,6 +16,33 @@
#define GL_GLES_PROTOTYPES 0
#include <GLES3/gl32.h>
#define GL_R8 0x8229
#define GL_R16 0x822A
#define GL_RG8 0x822B
#define GL_RG16 0x822C
#define GL_R16F 0x822D
#define GL_R32F 0x822E
#define GL_RG16F 0x822F
#define GL_RG32F 0x8230
#define GL_R8I 0x8231
#define GL_R8UI 0x8232
#define GL_R16I 0x8233
#define GL_R16UI 0x8234
#define GL_R32I 0x8235
#define GL_R32UI 0x8236
#define GL_RG8I 0x8237
#define GL_RG8UI 0x8238
#define GL_RG16I 0x8239
#define GL_RG16UI 0x823A
#define GL_RG32I 0x823B
#define GL_RG32UI 0x823C
#define GL_RGBA16 0x805B
#define GL_BGRA8_EXT 0x93A1
#define GL_R16_SNORM 0x8F98
#define GL_RG16_SNORM 0x8F99
#define GL_RGB16_SNORM 0x8F9A
#define GL_RGBA16_SNORM 0x8F9B
typedef void(*GLFunction)(void);
PulseBackendFlags OpenGLCheckSupport(PulseBackendFlags candidates, PulseShaderFormatsFlags shader_formats_used); // Return PULSE_BACKEND_OPENGL in case of success and PULSE_BACKEND_INVALID otherwise

View File

@@ -91,6 +91,37 @@ void OpenGLBindUniformData(PulseComputePass pass, uint32_t slot, const void* dat
void OpenGLBindStorageImages(PulseComputePass pass, const PulseImage* images, uint32_t num_images)
{
PulseImageUsageFlags usage = images[0]->usage;
bool is_readwrite = (usage & PULSE_IMAGE_USAGE_STORAGE_WRITE) != 0;
PulseImage* array = is_readwrite ? pass->readwrite_images : pass->readonly_images;
OpenGLComputePass* opengl_pass = OPENGL_RETRIEVE_DRIVER_DATA_AS(pass, OpenGLComputePass*);
for(uint32_t i = 0; i < num_images; i++)
{
if(is_readwrite && (images[i]->usage & PULSE_IMAGE_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 image with read-write images");
PulseSetInternalError(PULSE_ERROR_INVALID_IMAGE_USAGE);
return;
}
else if(!is_readwrite && (images[i]->usage & PULSE_IMAGE_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 image with read only images");
PulseSetInternalError(PULSE_ERROR_INVALID_IMAGE_USAGE);
return;
}
if(array[i] == images[i])
continue;
array[i] = images[i];
if(is_readwrite)
opengl_pass->should_recreate_write_bind_group = true;
else
opengl_pass->should_recreate_read_only_bind_group = true;
}
}
static void OpenGLBindBindsGroup(PulseComputePass pass)

View File

@@ -2,6 +2,8 @@
// 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"
@@ -32,7 +34,10 @@ PulseComputePipeline OpenGLCreateComputePipeline(PulseDevice device, const Pulse
PulseLogError(device->backend, "invalid shader format passed to PulseComputePipelineCreateInfo");
}
opengl_pipeline->program = opengl_device->glCreateShaderProgramv(device, GL_COMPUTE_SHADER, 1, (const GLchar**)(&info->code));
uint8_t* code = (uint8_t*)calloc(info->code_size + 1, 1);
memcpy(code, info->code, info->code_size);
opengl_pipeline->program = opengl_device->glCreateShaderProgramv(device, GL_COMPUTE_SHADER, 1, (const GLchar**)(&code));
GLint linked = GL_FALSE;
opengl_device->glGetProgramiv(device, opengl_pipeline->program, GL_LINK_STATUS, &linked);
if(linked != GL_TRUE)
@@ -52,11 +57,14 @@ PulseComputePipeline OpenGLCreateComputePipeline(PulseDevice device, const Pulse
}
opengl_device->glDeleteProgram(device, opengl_pipeline->program);
free(code);
free(opengl_pipeline);
free(pipeline);
return PULSE_NULL_HANDLE;
}
free(code);
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);

View File

@@ -212,6 +212,20 @@ PulseDevice OpenGLCreateDevice(PulseBackend backend, PulseDevice* forbiden_devic
pulse_device->driver_data = device;
pulse_device->backend = backend;
const char* core_extensions[] = {
"GL_ARB_texture_rg",
"GL_EXT_texture_storage",
"GL_EXT_texture_snorm",
};
const char* es_extensions[] = {
"GL_EXT_texture_rg",
"GL_EXT_texture_storage",
"GL_EXT_texture_snorm",
};
bool is_core = backend->backend == PULSE_BACKEND_OPENGL;
#ifdef PULSE_PLAT_WINDOWS
// WGL support
if(opengl_device->context_type == OPENGL_CONTEXT_WGL)
@@ -221,11 +235,25 @@ PulseDevice OpenGLCreateDevice(PulseBackend backend, PulseDevice* forbiden_devic
}
else
{
EGLLoadInstance(&device->egl_instance, forbiden_devices, forbiden_devices_count, backend->backend == PULSE_BACKEND_OPENGL_ES);
if(!EGLLoadInstance(&device->egl_instance, is_core ? core_extensions : es_extensions, PULSE_SIZEOF_ARRAY(is_core ? core_extensions : es_extensions), forbiden_devices, forbiden_devices_count, !is_core))
{
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(backend))
PulseLogError(backend, "could not load EGL instance");
free(device);
free(pulse_device);
return PULSE_NULL_HANDLE;
}
device->context_type = OPENGL_CONTEXT_EGL;
}
#else
EGLLoadInstance(&device->egl_instance, forbiden_devices, forbiden_devices_count, backend->backend == PULSE_BACKEND_OPENGL_ES);
if(!EGLLoadInstance(&device->egl_instance, is_core ? core_extensions : es_extensions, PULSE_SIZEOF_ARRAY(is_core ? core_extensions : es_extensions), forbiden_devices, forbiden_devices_count, !is_core))
{
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(backend))
PulseLogError(backend, "could not load EGL instance");
free(device);
free(pulse_device);
return PULSE_NULL_HANDLE;
}
device->context_type = OPENGL_CONTEXT_EGL;
#endif

View File

@@ -7,9 +7,77 @@
#include "../../PulseInternal.h"
#include "OpenGL.h"
#include "OpenGLImage.h"
#include "OpenGLDevice.h"
#include "OpenGLCommandList.h"
static GLenum PulseImageFormatToGLInternalFormat[] = {
GL_INVALID_ENUM, // INVALID
GL_R8, // A8_UNORM
GL_R8, // R8_UNORM
GL_RG8, // R8G8_UNORM
GL_RGBA8, // R8G8B8A8_UNORM
GL_R16, // R16_UNORM
GL_RG16, // R16G16_UNORM
GL_RGBA16, // R16G16B16A16_UNORM
GL_RGB10_A2, // R10G10B10A2_UNORM
GL_RGB565, // B5G6R5_UNORM
GL_RGB5_A1, // B5G5R5A1_UNORM
GL_INVALID_ENUM, // B4G4R4A4_UNORM
GL_BGRA8_EXT, // B8G8R8A8_UNORM
GL_INVALID_ENUM, // BC1_UNORM
GL_INVALID_ENUM, // BC2_UNORM
GL_INVALID_ENUM, // BC3_UNORM
GL_INVALID_ENUM, // BC4_UNORM
GL_INVALID_ENUM, // BC5_UNORM
GL_INVALID_ENUM, // BC7_UNORM
GL_INVALID_ENUM, // BC6H_FLOAT
GL_INVALID_ENUM, // BC6H_UFLOAT
GL_R8_SNORM, // R8_SNORM
GL_RG8_SNORM, // R8G8_SNORM
GL_RGBA8_SNORM, // R8G8B8A8_SNORM
GL_R16_SNORM, // R16_SNORM
GL_RG16_SNORM, // R16G16_SNORM
GL_RGBA16_SNORM, // R16G16B16A16_SNORM
GL_R16F, // R16_FLOAT
GL_RG16F, // R16G16_FLOAT
GL_RGBA16F, // R16G16B16A16_FLOAT
GL_R32F, // R32_FLOAT
GL_RG32F, // R32G32_FLOAT
GL_RGBA32F, // R32G32B32A32_FLOAT
GL_R11F_G11F_B10F, // R11G11B10_UFLOAT
GL_R8UI, // R8_UINT
GL_RG8UI, // R8G8_UINT
GL_RGBA8UI, // R8G8B8A8_UINT
GL_R16UI, // R16_UINT
GL_RG16UI, // R16G16_UINT
GL_RGBA16UI, // R16G16B16A16_UINT
GL_R32UI, // R32_UINT
GL_RG32UI, // R32G32_UINT
GL_RGBA32UI, // R32G32B32A32_UINT
GL_R8I, // R8_INT
GL_RG8I, // R8G8_INT
GL_RGBA8I, // R8G8B8A8_INT
GL_R16I, // R16_INT
GL_RG16I, // R16G16_INT
GL_RGBA16I, // R16G16B16A16_INT
GL_R32I, // R32_INT
GL_RG32I, // R32G32_INT
GL_RGBA32I, // R32G32B32A32_INT
};
PULSE_STATIC_ASSERT(PulseImageFormatToWGPUTextureFormat, (sizeof(PulseImageFormatToGLInternalFormat) / sizeof(GLenum)) == PULSE_IMAGE_FORMAT_MAX_ENUM);
PulseImage OpenGLCreateImage(PulseDevice device, const PulseImageCreateInfo* create_infos)
{
OpenGLDevice* opengl_device = OPENGL_RETRIEVE_DRIVER_DATA_AS(device, OpenGLDevice*);
PulseImageHandler* image = (PulseImageHandler*)calloc(1, sizeof(PulseImageHandler));
PULSE_CHECK_ALLOCATION_RETVAL(image, PULSE_NULL_HANDLE);
OpenGLImage* opengl_image = (OpenGLImage*)calloc(1, sizeof(OpenGLImage));
PULSE_CHECK_ALLOCATION_RETVAL(opengl_image, PULSE_NULL_HANDLE);
return image;
}
bool OpenGLIsImageFormatValid(PulseDevice device, PulseImageFormat format, PulseImageType type, PulseImageUsageFlags usage)
@@ -26,4 +94,7 @@ bool OpenGLBlitImage(PulseCommandList cmd, const PulseImageRegion* src, const Pu
void OpenGLDestroyImage(PulseDevice device, PulseImage image)
{
OpenGLImage* opengl_image = OPENGL_RETRIEVE_DRIVER_DATA_AS(image, OpenGLImage*);
free(opengl_image);
free(image);
}

View File

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

View File

@@ -60,6 +60,8 @@
for(size_t defrag_i = start; defrag_i < size - 1; defrag_i++) \
array[defrag_i] = array[defrag_i + 1]; \
#define PULSE_SIZEOF_ARRAY(x) ((sizeof(x) / sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
#define PULSE_CHECK_COMMAND_LIST_STATE_RETVAL(cmd, retval) \
do { \
if(cmd->state != PULSE_COMMAND_LIST_STATE_RECORDING) \

View File

@@ -0,0 +1,39 @@
#version 310 es
// compute shader - this file was generated by NZSL compiler (Nazara Shading Language)
precision highp int;
#if GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
// header end
struct Input
{
uvec3 indices;
};
// struct SSBO omitted (used as UBO/SSBO)
layout(binding = 0, std430) readonly buffer _nzslBindingread_ssbo
{
uint data[];
} read_ssbo;
layout(binding = 1, std430) writeonly buffer _nzslBindingwrite_ssbo
{
uint data[];
} write_ssbo;
void main()
{
Input input_;
input_.indices = gl_GlobalInvocationID;
write_ssbo.data[input_.indices.x * input_.indices.y] = read_ssbo.data[input_.indices.x * input_.indices.y];
}

View File

@@ -0,0 +1,36 @@
#version 310 es
// compute shader - this file was generated by NZSL compiler (Nazara Shading Language)
precision highp int;
#if GL_FRAGMENT_PRECISION_HIGH
precision highp float;
precision highp image2D;
#else
precision mediump float;
precision mediump image2D;
#endif
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
// header end
struct Input
{
uvec3 indices;
};
// struct SSBO omitted (used as UBO/SSBO)
layout(binding = 0, rgba8) uniform readonly image2D read_texture;
layout(binding = 1, std430) readonly buffer _nzslBindingread_ssbo
{
uint data[];
} read_ssbo;
void main()
{
Input input_;
input_.indices = gl_GlobalInvocationID;
}

View File

@@ -0,0 +1,42 @@
#version 310 es
// compute shader - this file was generated by NZSL compiler (Nazara Shading Language)
precision highp int;
#if GL_FRAGMENT_PRECISION_HIGH
precision highp float;
precision highp image2D;
#else
precision mediump float;
precision mediump image2D;
#endif
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
// header end
struct Input
{
uvec3 indices;
};
// struct SSBO omitted (used as UBO/SSBO)
layout(binding = 0, rgba8) uniform readonly image2D read_texture;
layout(binding = 1, std430) readonly buffer _nzslBindingread_ssbo
{
uint data[];
} read_ssbo;
layout(binding = 2) uniform image2D write_texture;
layout(binding = 3, std430) writeonly buffer _nzslBindingwrite_ssbo
{
uint data[];
} write_ssbo;
void main()
{
Input input_;
input_.indices = gl_GlobalInvocationID;
}

26
Tests/Shaders/Vulkan-OpenGL/Simple.comp.glsl git.filemode.normal_file
View File

@@ -0,0 +1,26 @@
#version 310 es
// compute shader - this file was generated by NZSL compiler (Nazara Shading Language)
precision highp int;
#if GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
// header end
struct Input
{
uvec3 indices;
};
void main()
{
Input input_;
input_.indices = gl_GlobalInvocationID;
}

View File

@@ -0,0 +1,34 @@
#version 310 es
// compute shader - this file was generated by NZSL compiler (Nazara Shading Language)
precision highp int;
#if GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
// header end
struct Input
{
uvec3 indices;
};
// struct SSBO omitted (used as UBO/SSBO)
layout(binding = 0, std430) buffer _nzslBindingssbo
{
uint data[];
} ssbo;
void main()
{
Input input_;
input_.indices = gl_GlobalInvocationID;
ssbo.data[input_.indices.x * input_.indices.y] = uint(-1);
}

View File

@@ -0,0 +1,36 @@
#version 310 es
// compute shader - this file was generated by NZSL compiler (Nazara Shading Language)
precision highp int;
#if GL_FRAGMENT_PRECISION_HIGH
precision highp float;
precision highp image2D;
#else
precision mediump float;
precision mediump image2D;
#endif
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
// header end
struct Input
{
uvec3 indices;
};
// struct SSBO omitted (used as UBO/SSBO)
layout(binding = 0, rgba8) uniform image2D write_texture;
layout(binding = 1, std430) buffer _nzslBindingwrite_ssbo
{
uint data[];
} write_ssbo;
void main()
{
Input input_;
input_.indices = gl_GlobalInvocationID;
}

View File

@@ -79,11 +79,11 @@ function nzsl(backend)
batchcmds:show_progress(opt.progress, "${color.build.object}compiling.shader %s", shaderfile)
local argv = {}
if backend == Backend.VULKAN then
argv = { "--compile=spv-header", "--optimize" }
argv = { "--compile=spv-header" }
elseif backend == Backend.OPENGL_ES then
argv = { "--compile=glsl-header", "--optimize", "--gl-version", "310", "--gl-es", "--gl-bindingmap" }
argv = { "--compile=glsl,glsl-header", "--gl-version", "310", "--gl-es", "--gl-bindingmap" }
else
argv = { "--compile=glsl-header", "--optimize", "--gl-version", "310", "--gl-bindingmap" }
argv = { "--compile=glsl,glsl-header", "--gl-version", "310", "--gl-bindingmap" }
end
if outputdir then
batchcmds:mkdir(outputdir)