orca/src/gles_api_bind_manual.c

1133 lines
33 KiB
C

//------------------------------------------------------------------------
// Manual pointer size checking functions
//------------------------------------------------------------------------
u64 orca_gles_check_cstring(IM3Runtime runtime, const char* ptr)
{
uint32_t memorySize = 0;
char* memory = (char*)m3_GetMemory(runtime, &memorySize, 0);
//NOTE: Here we are guaranteed that ptr is in [ memory ; memory + memorySize [
// hence (memory + memorySize) - ptr is representable by size_t and <= memorySize
size_t maxLen = (memory + memorySize) - ptr;
u64 len = strnlen(ptr, maxLen);
if(len == maxLen)
{
//NOTE: string overflows wasm memory, return a length that will trigger the bounds check
len = maxLen + 1;
}
return(len+1); //include null-terminator
}
u64 orca_gl_type_size(GLenum type)
{
u64 size = 8;
switch(type)
{
case GL_UNSIGNED_BYTE:
case GL_BYTE:
size = sizeof(GLbyte);
break;
case GL_UNSIGNED_SHORT:
case GL_SHORT:
case GL_HALF_FLOAT:
size = sizeof(GLshort);
break;
case GL_UNSIGNED_INT:
case GL_INT:
case GL_FIXED:
case GL_INT_2_10_10_10_REV:
case GL_UNSIGNED_INT_2_10_10_10_REV:
size = sizeof(GLint);
break;
case GL_FLOAT:
size = sizeof(GLfloat);
break;
case GL_DOUBLE:
size = sizeof(GLdouble);
break;
default:
ORCA_ASSERT(0, "unknown GLenum type %i", type);
}
return(size);
}
u64 orca_gl_format_count(GLenum format)
{
u64 count = 4;
switch(format)
{
case GL_RED:
case GL_RED_INTEGER:
case GL_DEPTH_COMPONENT:
case GL_STENCIL_INDEX:
case GL_LUMINANCE:
case GL_ALPHA:
count = 1;
break;
case GL_RG:
case GL_RG_INTEGER:
case GL_DEPTH_STENCIL:
case GL_LUMINANCE_ALPHA:
count = 2;
break;
case GL_RGB:
case GL_RGB_INTEGER:
count = 3;
break;
case GL_RGBA:
case GL_RGBA_INTEGER:
count = 4;
break;
default:
ORCA_ASSERT(0, "unknow GLenum format %i", format);
}
return(count);
}
typedef struct orca_gles_impl_limits
{
bool init;
int maxDrawBuffers;
int numCompressedTextureFormats;
int numProgramBinaryFormats;
int numShaderBinaryFormats;
//...
} orca_gles_impl_limits;
orca_gles_impl_limits __orcaGLESImplLimits = {0};
u64 orca_glGet_data_length(GLenum pname)
{
if(!__orcaGLESImplLimits.init)
{
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &__orcaGLESImplLimits.maxDrawBuffers);
glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &__orcaGLESImplLimits.numCompressedTextureFormats);
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &__orcaGLESImplLimits.numProgramBinaryFormats);
glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &__orcaGLESImplLimits.numShaderBinaryFormats);
}
u64 count = 8;
if(pname >= GL_DRAW_BUFFER0 && pname < GL_DRAW_BUFFER0 + __orcaGLESImplLimits.maxDrawBuffers)
{
count = 1;
}
else
{
switch(pname)
{
case GL_ACTIVE_TEXTURE:
case GL_ALPHA_BITS:
case GL_ARRAY_BUFFER_BINDING:
case GL_BLEND:
case GL_BLEND_DST_ALPHA:
case GL_BLEND_DST_RGB:
case GL_BLEND_EQUATION_ALPHA:
case GL_BLEND_EQUATION_RGB:
case GL_BLEND_SRC_ALPHA:
case GL_BLEND_SRC_RGB:
case GL_BLUE_BITS:
case GL_CONTEXT_FLAGS:
case GL_CONTEXT_ROBUST_ACCESS:
case GL_COPY_READ_BUFFER_BINDING:
case GL_COPY_WRITE_BUFFER_BINDING:
case GL_CULL_FACE:
case GL_CULL_FACE_MODE:
case GL_CURRENT_PROGRAM:
case GL_DEBUG_GROUP_STACK_DEPTH:
case GL_DEBUG_LOGGED_MESSAGES:
case GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH:
case GL_DEPTH_BITS:
case GL_DEPTH_CLEAR_VALUE:
case GL_DEPTH_FUNC:
case GL_DEPTH_TEST:
case GL_DEPTH_WRITEMASK:
case GL_DISPATCH_INDIRECT_BUFFER_BINDING:
case GL_DITHER:
case GL_DRAW_FRAMEBUFFER_BINDING:
case GL_ELEMENT_ARRAY_BUFFER_BINDING:
case GL_FRAGMENT_INTERPOLATION_OFFSET_BITS:
case GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
case GL_FRONT_FACE:
case GL_GENERATE_MIPMAP_HINT:
case GL_GREEN_BITS:
case GL_IMAGE_BINDING_LAYERED:
case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
case GL_IMPLEMENTATION_COLOR_READ_TYPE:
case GL_LAYER_PROVOKING_VERTEX:
case GL_LINE_WIDTH:
case GL_MAJOR_VERSION:
case GL_MAX_3D_TEXTURE_SIZE:
case GL_MAX_ARRAY_TEXTURE_LAYERS:
case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS:
case GL_MAX_COLOR_ATTACHMENTS:
case GL_MAX_COMBINED_ATOMIC_COUNTERS:
case GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS:
case GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS:
case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
case GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS:
case GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS:
case GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS:
case GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS:
case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
case GL_MAX_COMBINED_UNIFORM_BLOCKS:
case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS:
case GL_MAX_COMPUTE_ATOMIC_COUNTERS:
case GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS:
case GL_MAX_COMPUTE_IMAGE_UNIFORMS:
case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS:
case GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS:
case GL_MAX_COMPUTE_UNIFORM_BLOCKS:
case GL_MAX_COMPUTE_UNIFORM_COMPONENTS:
case GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS:
case GL_MAX_COMPUTE_WORK_GROUP_COUNT:
case GL_MAX_COMPUTE_WORK_GROUP_SIZE:
case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
case GL_MAX_DEBUG_GROUP_STACK_DEPTH:
case GL_MAX_DEBUG_LOGGED_MESSAGES:
case GL_MAX_DEBUG_MESSAGE_LENGTH:
case GL_MAX_DEPTH_TEXTURE_SAMPLES:
case GL_MAX_DRAW_BUFFERS:
case GL_MAX_ELEMENT_INDEX:
case GL_MAX_ELEMENTS_INDICES:
case GL_MAX_ELEMENTS_VERTICES:
case GL_MAX_FRAGMENT_ATOMIC_COUNTERS:
case GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS:
case GL_MAX_FRAGMENT_IMAGE_UNIFORMS:
case GL_MAX_FRAGMENT_INPUT_COMPONENTS:
case GL_MAX_FRAGMENT_INTERPOLATION_OFFSET:
case GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS:
case GL_MAX_FRAGMENT_UNIFORM_BLOCKS:
case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
case GL_MAX_FRAMEBUFFER_HEIGHT:
case GL_MAX_FRAMEBUFFER_LAYERS:
case GL_MAX_FRAMEBUFFER_SAMPLES:
case GL_MAX_FRAMEBUFFER_WIDTH:
case GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS:
case GL_MAX_GEOMETRY_ATOMIC_COUNTERS:
case GL_MAX_GEOMETRY_IMAGE_UNIFORMS:
case GL_MAX_GEOMETRY_INPUT_COMPONENTS:
case GL_MAX_GEOMETRY_OUTPUT_COMPONENTS:
case GL_MAX_GEOMETRY_OUTPUT_VERTICES:
case GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS:
case GL_MAX_GEOMETRY_SHADER_INVOCATIONS:
case GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS:
case GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS:
case GL_MAX_GEOMETRY_UNIFORM_BLOCKS:
case GL_MAX_GEOMETRY_UNIFORM_COMPONENTS:
case GL_MAX_INTEGER_SAMPLES:
case GL_MAX_LABEL_LENGTH:
case GL_MAX_PROGRAM_TEXEL_OFFSET:
case GL_MAX_RENDERBUFFER_SIZE:
case GL_MAX_SAMPLE_MASK_WORDS:
case GL_MAX_SAMPLES:
case GL_MAX_SERVER_WAIT_TIMEOUT:
case GL_MAX_SHADER_STORAGE_BLOCK_SIZE:
case GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS:
case GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS:
case GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS:
case GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS:
case GL_MAX_TESS_CONTROL_INPUT_COMPONENTS:
case GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS:
case GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS:
case GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS:
case GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS:
case GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS:
case GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS:
case GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS:
case GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS:
case GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS:
case GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS:
case GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS:
case GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS:
case GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS:
case GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS:
case GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS:
case GL_MAX_TESS_GEN_LEVEL:
case GL_MAX_TESS_PATCH_COMPONENTS:
case GL_MAX_TEXTURE_BUFFER_SIZE:
case GL_MAX_TEXTURE_IMAGE_UNITS:
case GL_MAX_TEXTURE_LOD_BIAS:
case GL_MAX_TEXTURE_SIZE:
case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
case GL_MAX_UNIFORM_BLOCK_SIZE:
case GL_MAX_UNIFORM_BUFFER_BINDINGS:
case GL_MAX_UNIFORM_LOCATIONS:
case GL_MAX_VARYING_COMPONENTS:
case GL_MAX_VARYING_VECTORS:
case GL_MAX_VERTEX_ATOMIC_COUNTERS:
case GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS:
case GL_MAX_VERTEX_ATTRIB_BINDINGS:
case GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET:
case GL_MAX_VERTEX_ATTRIBS:
case GL_MAX_VERTEX_IMAGE_UNIFORMS:
case GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS:
case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
case GL_MAX_VERTEX_OUTPUT_COMPONENTS:
case GL_MAX_VERTEX_UNIFORM_BLOCKS:
case GL_MAX_VERTEX_UNIFORM_COMPONENTS:
case GL_MAX_VERTEX_UNIFORM_VECTORS:
case GL_MIN_FRAGMENT_INTERPOLATION_OFFSET:
case GL_MIN_PROGRAM_TEXEL_OFFSET:
case GL_MIN_SAMPLE_SHADING_VALUE:
case GL_MINOR_VERSION:
case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
case GL_NUM_EXTENSIONS:
case GL_NUM_PROGRAM_BINARY_FORMATS:
case GL_NUM_SHADER_BINARY_FORMATS:
case GL_PACK_ALIGNMENT:
case GL_PACK_ROW_LENGTH:
case GL_PACK_SKIP_PIXELS:
case GL_PACK_SKIP_ROWS:
case GL_PATCH_VERTICES:
case GL_PIXEL_PACK_BUFFER_BINDING:
case GL_PIXEL_UNPACK_BUFFER_BINDING:
case GL_POLYGON_OFFSET_FACTOR:
case GL_POLYGON_OFFSET_FILL:
case GL_POLYGON_OFFSET_UNITS:
case GL_PRIMITIVE_RESTART_FIXED_INDEX:
case GL_PROGRAM_PIPELINE_BINDING:
case GL_RASTERIZER_DISCARD:
case GL_READ_BUFFER:
case GL_READ_FRAMEBUFFER_BINDING:
case GL_RED_BITS:
case GL_RENDERBUFFER_BINDING:
case GL_RESET_NOTIFICATION_STRATEGY:
case GL_SAMPLE_ALPHA_TO_COVERAGE:
case GL_SAMPLE_BUFFERS:
case GL_SAMPLE_COVERAGE:
case GL_SAMPLE_COVERAGE_INVERT:
case GL_SAMPLE_COVERAGE_VALUE:
case GL_SAMPLE_MASK_VALUE:
case GL_SAMPLE_SHADING:
case GL_SAMPLER_BINDING:
case GL_SAMPLES:
case GL_SCISSOR_TEST:
case GL_SHADER_COMPILER:
case GL_SHADER_STORAGE_BUFFER_BINDING:
case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT:
case GL_SHADER_STORAGE_BUFFER_SIZE:
case GL_SHADER_STORAGE_BUFFER_START:
case GL_STENCIL_BACK_FAIL:
case GL_STENCIL_BACK_FUNC:
case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
case GL_STENCIL_BACK_PASS_DEPTH_PASS:
case GL_STENCIL_BACK_REF:
case GL_STENCIL_BACK_VALUE_MASK:
case GL_STENCIL_BACK_WRITEMASK:
case GL_STENCIL_BITS:
case GL_STENCIL_CLEAR_VALUE:
case GL_STENCIL_FAIL:
case GL_STENCIL_FUNC:
case GL_STENCIL_PASS_DEPTH_FAIL:
case GL_STENCIL_PASS_DEPTH_PASS:
case GL_STENCIL_REF:
case GL_STENCIL_TEST:
case GL_STENCIL_VALUE_MASK:
case GL_STENCIL_WRITEMASK:
case GL_SUBPIXEL_BITS:
case GL_TEXTURE_BINDING_2D:
case GL_TEXTURE_BINDING_2D_ARRAY:
case GL_TEXTURE_BINDING_3D:
case GL_TEXTURE_BINDING_BUFFER:
case GL_TEXTURE_BINDING_CUBE_MAP:
case GL_TEXTURE_BINDING_2D_MULTISAMPLE:
case GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY:
case GL_TEXTURE_BINDING_CUBE_MAP_ARRAY:
case GL_TEXTURE_BUFFER_BINDING:
case GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT:
case GL_TRANSFORM_FEEDBACK_BINDING:
case GL_TRANSFORM_FEEDBACK_ACTIVE:
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
case GL_TRANSFORM_FEEDBACK_PAUSED:
case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
case GL_TRANSFORM_FEEDBACK_BUFFER_START:
case GL_UNIFORM_BUFFER_BINDING:
case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
case GL_UNIFORM_BUFFER_SIZE:
case GL_UNIFORM_BUFFER_START:
case GL_UNPACK_ALIGNMENT:
case GL_UNPACK_IMAGE_HEIGHT:
case GL_UNPACK_ROW_LENGTH:
case GL_UNPACK_SKIP_IMAGES:
case GL_UNPACK_SKIP_PIXELS:
case GL_UNPACK_SKIP_ROWS:
case GL_VERTEX_ARRAY_BINDING:
case GL_VERTEX_BINDING_DIVISOR:
case GL_VERTEX_BINDING_OFFSET:
case GL_VERTEX_BINDING_STRIDE:
case GL_TEXTURE_2D:
case GL_TEXTURE_3D:
count = 1;
break;
case GL_ALIASED_LINE_WIDTH_RANGE:
case GL_ALIASED_POINT_SIZE_RANGE:
case GL_DEPTH_RANGE:
case GL_MAX_VIEWPORT_DIMS:
case GL_MULTISAMPLE_LINE_WIDTH_RANGE:
count = 2;
break;
case GL_BLEND_COLOR:
case GL_COLOR_CLEAR_VALUE:
case GL_COLOR_WRITEMASK:
case GL_SCISSOR_BOX:
case GL_VIEWPORT:
count = 4;
break;
case GL_PRIMITIVE_BOUNDING_BOX:
count = 8;
break;
case GL_COMPRESSED_TEXTURE_FORMATS:
count = __orcaGLESImplLimits.numCompressedTextureFormats;
break;
case GL_PROGRAM_BINARY_FORMATS:
count = __orcaGLESImplLimits.numProgramBinaryFormats;
break;
case GL_SHADER_BINARY_FORMATS:
count = __orcaGLESImplLimits.numShaderBinaryFormats;
break;
default:
ORCA_ASSERT(0, "unknown GLenum pname %i", pname);
break;
}
}
return(count);
}
u64 orca_glDrawElements_indices_length(IM3Runtime runtime, GLsizei count, GLenum type)
{
return(orca_gl_type_size(type)*count);
}
u64 orca_glGetBooleanv_data_length(IM3Runtime runtime, GLenum pname)
{
return(orca_glGet_data_length(pname));
}
u64 orca_glGetBufferParameteriv_params_length(IM3Runtime runtime, GLenum pname)
{
//NOTE: all pnames return a single value in 3.1
return(1);
}
u64 orca_glGetFloatv_data_length(IM3Runtime runtime, GLenum pname)
{
return(orca_glGet_data_length(pname));
}
u64 orca_glGetFramebufferAttachmentParameteriv_params_length(IM3Runtime runtime, GLenum pname)
{
//NOTE: all pnames return a single value in 3.1
return(1);
}
u64 orca_glGetIntegerv_data_length(IM3Runtime runtime, GLenum pname)
{
return(orca_glGet_data_length(pname));
}
u64 orca_glGetProgramiv_params_length(IM3Runtime runtime, GLenum pname)
{
//NOTE: all pnames return a single value in 3.1
return(1);
}
u64 orca_glGetRenderbufferParameteriv_params_length(IM3Runtime runtime, GLenum pname)
{
//NOTE: all pnames return a single value in 3.1
return(1);
}
u64 orca_glGetShaderiv_params_length(IM3Runtime runtime, GLenum pname)
{
//NOTE: all pnames return a single value in 3.1
return(1);
}
u64 orca_glTexParameter_params_length_generic(GLenum pname)
{
u64 count = 4;
if(pname == GL_TEXTURE_BORDER_COLOR)
{
count = 4;
}
else
{
count = 1;
}
return(count);
}
u64 orca_glGetTexParameterfv_params_length(IM3Runtime runtime, GLenum pname)
{
return(orca_glTexParameter_params_length_generic(pname));
}
u64 orca_glGetTexParameteriv_params_length(IM3Runtime runtime, GLenum pname)
{
return(orca_glTexParameter_params_length_generic(pname));
}
u64 orca_glReadPixels_pixels_length(IM3Runtime runtime, GLenum format, GLenum type, GLsizei width, GLsizei height)
{
u64 count = width*height*orca_gl_type_size(type)*orca_gl_format_count(format);
return(count);
}
u64 orca_glTexImage2D_pixels_length(IM3Runtime runtime, GLenum format, GLenum type, GLsizei width, GLsizei height)
{
u64 count = width*height*orca_gl_type_size(type)*orca_gl_format_count(format);
return(count);
}
u64 orca_glTexParameterfv_params_length(IM3Runtime runtime, GLenum pname)
{
return(orca_glTexParameter_params_length_generic(pname));
}
u64 orca_glTexParameteriv_params_length(IM3Runtime runtime, GLenum pname)
{
return(orca_glTexParameter_params_length_generic(pname));
}
u64 orca_glTexSubImage2D_pixels_length(IM3Runtime runtime, GLenum format, GLenum type, GLsizei width, GLsizei height)
{
u64 count = width*height*orca_gl_type_size(type)*orca_gl_format_count(format);
return(count);
}
u64 orca_glDrawRangeElements_indices_length(IM3Runtime runtime, GLsizei count, GLenum type)
{
return(count*orca_gl_type_size(type));
}
u64 orca_glTexImage3D_pixels_length(IM3Runtime runtime, GLenum format, GLenum type, GLsizei width, GLsizei height, GLsizei depth)
{
u64 count = width*height*depth*orca_gl_type_size(type)*orca_gl_format_count(format);
return(count);
}
u64 orca_glTexSubImage3D_pixels_length(IM3Runtime runtime, GLenum format, GLenum type, GLsizei width, GLsizei height, GLsizei depth)
{
u64 count = width*height*depth*orca_gl_type_size(type)*orca_gl_format_count(format);
return(count);
}
u64 orca_glGetQueryiv_params_length(IM3Runtime runtime, GLenum pname)
{
//NOTE: all pnames return a single value in 3.1
return(1);
}
u64 orca_glGetQueryObjectuiv_params_length(IM3Runtime runtime, GLenum pname)
{
//NOTE: all pnames return a single value in 3.1
return(1);
}
u64 orca_glGetIntegeri_v_data_length(IM3Runtime runtime, GLenum target)
{
return(orca_glGet_data_length(target));
}
u64 orca_glVertexAttribIPointer_pointer_length(IM3Runtime runtime, GLint size, GLenum type, GLsizei stride)
{
//WARN: pointer param of glVertexAttribPointer is actually treated as an offset,
// so, we don't need to check if this points to valid memory ??
return(0);
}
u64 orca_glClearBuffer_value_length_generic(GLenum buffer)
{
u64 count = 4;
switch(buffer)
{
case GL_COLOR:
count = 4;
break;
case GL_DEPTH:
case GL_STENCIL:
count = 1;
break;
default:
ORCA_ASSERT(0, "invalid buffer enum for glClearBuffer()");
}
return(count);
}
u64 orca_glClearBufferiv_value_length(IM3Runtime runtime, GLenum buffer)
{
return(orca_glClearBuffer_value_length_generic(buffer));
}
u64 orca_glClearBufferuiv_value_length(IM3Runtime runtime, GLenum buffer)
{
return(orca_glClearBuffer_value_length_generic(buffer));
}
u64 orca_glClearBufferfv_value_length(IM3Runtime runtime, GLenum buffer)
{
return(orca_glClearBuffer_value_length_generic(buffer));
}
u64 orca_glGetUniformIndices_uniformIndices_length(IM3Runtime runtime, GLsizei uniformCount)
{
return(uniformCount);
}
u64 orca_glGetActiveUniformsiv_params_length(IM3Runtime runtime, GLsizei uniformCount, GLenum pname)
{
return(uniformCount);
}
u64 orca_glGetActiveUniformBlockiv_params_length(IM3Runtime runtime, GLuint program, GLuint uniformBlockIndex, GLenum pname)
{
u64 count;
if(pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
{
GLint param;
glGetActiveUniformBlockiv(program, uniformBlockIndex, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &param);
count = param;
}
else
{
count = 1;
}
return(count);
}
u64 orca_glDrawElementsInstanced_indices_length(IM3Runtime runtime, GLsizei count, GLenum type)
{
return(count*orca_gl_type_size(type));
}
u64 orca_glGetInteger64v_data_length(IM3Runtime runtime, GLenum pname)
{
return(orca_glGet_data_length(pname));
}
u64 orca_glGetInteger64i_v_data_length(IM3Runtime runtime, GLenum target)
{
return(orca_glGet_data_length(target));
}
u64 orca_glGetBufferParameteri64v_params_length(IM3Runtime runtime, GLenum pname)
{
//NOTE: all pnames return a single value in 3.1
return(1);
}
u64 orca_glSamplerParameter_param_length_generic(GLenum pname)
{
//NOTE: same as texture parameter pnames
return(orca_glTexParameter_params_length_generic(pname));
}
u64 orca_glSamplerParameteriv_param_length(IM3Runtime runtime, GLenum pname)
{
return(orca_glSamplerParameter_param_length_generic(pname));
}
u64 orca_glSamplerParameterfv_param_length(IM3Runtime runtime, GLenum pname)
{
return(orca_glSamplerParameter_param_length_generic(pname));
}
u64 orca_glGetSamplerParameteriv_params_length(IM3Runtime runtime, GLenum pname)
{
return(orca_glSamplerParameter_param_length_generic(pname));
}
u64 orca_glGetSamplerParameterfv_params_length(IM3Runtime runtime, GLenum pname)
{
return(orca_glSamplerParameter_param_length_generic(pname));
}
u64 orca_glGetFramebufferParameteriv_params_length(IM3Runtime runtime, GLenum pname)
{
//NOTE: all pnames return a single value in 3.1
return(1);
}
u64 orca_glGetProgramInterfaceiv_params_length(IM3Runtime runtime, GLenum pname)
{
//NOTE: all pnames return a single value in 3.1
return(1);
}
u64 orca_glGetProgramPipelineiv_params_length(IM3Runtime runtime, GLenum pname)
{
//NOTE: all pnames return a single value in 3.1
return(1);
}
u64 orca_glGetBooleani_v_data_length(IM3Runtime runtime, GLenum target)
{
return(orca_glSamplerParameter_param_length_generic(target));
}
u64 orca_glGetMultisamplefv_val_length(IM3Runtime runtime, GLenum pname)
{
return(2);
}
u64 orca_glGetTexLevelParameteriv_params_length(IM3Runtime runtime, GLenum pname)
{
//NOTE: all pnames return a single value in 3.1
return(1);
}
u64 orca_glGetTexLevelParameterfv_params_length(IM3Runtime runtime, GLenum pname)
{
//NOTE: all pnames return a single value in 3.1
return(1);
}
//------------------------------------------------------------------------
// Uniforms size checking
//------------------------------------------------------------------------
u64 orca_glGetUniform_params_length_generic(GLuint program, GLint location)
{
//NOTE: This is super stupid but we can't get the size (or index) of a uniform directly from its location,
// so we have to iterate through all uniforms...
GLint maxUniformName = 0;
glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformName);
int uniformCount = 0;
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniformCount);
mem_arena_scope scratch = mem_scratch_begin();
char* name = mem_arena_alloc(scratch.arena, maxUniformName+1);
u64 count = 0;
bool found = false;
for(int i=0; i<uniformCount; i++)
{
GLsizei nameLength = 0;
GLint uniformSize = 0;
GLenum uniformType = 0;
glGetActiveUniform(program, i, maxUniformName, &nameLength, &uniformSize, &uniformType, name);
GLint uniformLocation = glGetUniformLocation(program, name);
if(uniformLocation == location)
{
count = uniformSize;
found = true;
break;
}
}
ORCA_ASSERT(found, "uniform location %i not found for program %i", location, program);
mem_scratch_end(scratch);
return(count);
}
u64 orca_glGetUniformfv_params_length(IM3Runtime runtime, GLuint program, GLint location)
{
return(orca_glGetUniform_params_length_generic(program, location));
}
u64 orca_glGetUniformiv_params_length(IM3Runtime runtime, GLuint program, GLint location)
{
return(orca_glGetUniform_params_length_generic(program, location));
}
u64 orca_glGetUniformuiv_params_length(IM3Runtime runtime, GLuint program, GLint location)
{
return(orca_glGetUniform_params_length_generic(program, location));
}
//------------------------------------------------------------------------
// Null-terminated parameters checking
//------------------------------------------------------------------------
u64 orca_glGetFragDataLocation_name_length(IM3Runtime runtime, const GLchar* name)
{
return(orca_gles_check_cstring(runtime, name));
}
u64 orca_glGetUniformBlockIndex_uniformBlockName_length(IM3Runtime runtime, const GLchar* uniformBlockName)
{
return(orca_gles_check_cstring(runtime, uniformBlockName));
}
u64 orca_glGetProgramResourceIndex_name_length(IM3Runtime runtime, const GLchar* name)
{
return(orca_gles_check_cstring(runtime, name));
}
u64 orca_glGetProgramResourceLocation_name_length(IM3Runtime runtime, const GLchar* name)
{
return(orca_gles_check_cstring(runtime, name));
}
u64 orca_glBindAttribLocation_name_length(IM3Runtime runtime, const GLchar* name)
{
return(orca_gles_check_cstring(runtime, name));
}
u64 orca_glGetAttribLocation_name_length(IM3Runtime runtime, const GLchar* name)
{
return(orca_gles_check_cstring(runtime, name));
}
u64 orca_glGetUniformLocation_name_length(IM3Runtime runtime, const GLchar* name)
{
return(orca_gles_check_cstring(runtime, name));
}
//------------------------------------------------------------------------
// Draw indirect length checks
//------------------------------------------------------------------------
typedef struct
{
u32 count;
u32 primCount;
u32 first;
u32 reserved;
} DrawArraysIndirectCommand;
u64 orca_glDrawArraysIndirect_indirect_length(IM3Runtime runtime, const void* indirect)
{
return(sizeof(DrawArraysIndirectCommand));
}
typedef struct
{
u32 count;
u32 instanceCount;
u32 firstIndex;
i32 baseVertex;
u32 reservedMustBeZero;
} DrawElementsIndirectCommand;
u64 orca_glDrawElementsIndirect_indirect_length(IM3Runtime runtime, const void* indirect)
{
return(sizeof(DrawElementsIndirectCommand));
}
//------------------------------------------------------------------------
// Fully manual bindings
//------------------------------------------------------------------------
const void* glShaderSource_stub(IM3Runtime runtime, IM3ImportContext _ctx, uint64_t * _sp, void * _mem)
{
i32 shader = *(i32*)&_sp[0];
i32 count = *(i32*)&_sp[1];
i32 stringArrayOffset = *(i32*)&_sp[2];
i32 lengthArrayOffset = *(i32*)&_sp[3];
int* stringOffsetArray = (int*)((char*)_mem + stringArrayOffset);
const char** stringArray = (const char**)mem_arena_alloc_array(mem_scratch(), char*, count);
for(int i=0; i<count; i++)
{
stringArray[i] = (char*)_mem + stringOffsetArray[i];
}
int* lengthArray = lengthArrayOffset ? (int*)((char*)_mem + lengthArrayOffset) : 0;
glShaderSource(shader, count, stringArray, lengthArray);
return(0);
}
const void* glGetVertexAttribPointerv_stub(IM3Runtime runtime, IM3ImportContext _ctx, uint64_t* _sp, void* _mem)
{
GLuint index = *(i32*)&_sp[0];
GLenum pname = *(i32*)&_sp[1];
i32* pointer = (i32*)((char*)_mem + *(u32*)&_sp[2]);
{
ORCA_ASSERT(((char*)pointer >= (char*)_mem) && (((char*)pointer - (char*)_mem) < m3_GetMemorySize(runtime)),
"parameter 'pointer' is out of bounds");
ORCA_ASSERT((char*)pointer + sizeof(i32) <= ((char*)_mem + m3_GetMemorySize(runtime)),
"parameter 'pointer' overflows wasm memory");
}
void* rawPointer = 0;
glGetVertexAttribPointerv(index, pname, &rawPointer);
//NOTE: pointer is actually a _byte offset_ into a GPU buffer. So we do _not_ convert it to a wasm pointer,
// but we need to truncate it to u32 size...
//WARN: can OpenGL return a byte offset > UINT_MAX ?
*pointer = (i32)(intptr_t)rawPointer;
return(0);
}
const void* glVertexAttribPointer_stub(IM3Runtime runtime, IM3ImportContext _ctx, uint64_t* _sp, void* _mem)
{
GLuint index = *(u32*)&_sp[0];
GLint size = *(i32*)&_sp[1];
GLenum type = *(i32*)&_sp[2];
GLboolean normalized = (GLboolean)*(i32*)&_sp[3];
GLsizei stride = *(i32*)&_sp[4];
//NOTE: pointer is interpreted as an offset if there's a non-null buffer bound to GL_ARRAY_BUFFER,
// or as a pointer otherwise. Since there's no way of checking the length of client vertex arrays,
// we just disable those.
GLint boundBuffer = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &boundBuffer);
if(boundBuffer != 0)
{
//NOTE: don't do bounds checking since pointer is really an offset in a GPU buffer
const void* pointer = (void*)(intptr_t)*(u32*)&_sp[5];
glVertexAttribPointer(index, size, type, normalized, stride, pointer);
}
else
{
//NOTE: we crash here before letting ANGLE crash because vertex attrib pointer is not set
ORCA_ASSERT("Calling glVertexAttribPointer with a GL_ARRAY_BUFFER binding of 0 is unsafe and disabled in Orca.");
}
return(0);
}
const void* glVertexAttribIPointer_stub(IM3Runtime runtime, IM3ImportContext _ctx, uint64_t* _sp, void* _mem)
{
GLuint index = *(u32*)&_sp[0];
GLint size = *(i32*)&_sp[1];
GLenum type = *(i32*)&_sp[2];
GLsizei stride = *(i32*)&_sp[3];
//NOTE: pointer is interpreted as an offset if there's a non-null buffer bound to GL_ARRAY_BUFFER,
// or as a pointer otherwise. Since there's no way of checking the length of client vertex arrays,
// we just disable those.
GLint boundBuffer = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &boundBuffer);
if(boundBuffer != 0)
{
//NOTE: don't do bounds checking since pointer is really an offset in a GPU buffer
const void* pointer = (void*)(intptr_t)*(u32*)&_sp[4];
glVertexAttribIPointer(index, size, type, stride, pointer);
}
else
{
ORCA_ASSERT(0, "Calling glVertexAttribIPointer with a GL_ARRAY_BUFFER binding of 0 is unsafe and disabled in Orca.");
}
return(0);
}
const void* glGetUniformIndices_stub(IM3Runtime runtime, IM3ImportContext _ctx, uint64_t* _sp, void* _mem)
{
GLuint program = (GLuint)*(i32*)&_sp[0];
GLsizei uniformCount = (GLsizei)*(i32*)&_sp[1];
u32* uniformNames = (u32*)((char*)_mem + *(u32*)&_sp[2]);
GLuint * uniformIndices = (GLuint *)((char*)_mem + *(u32*)&_sp[3]);
u64 memorySize = m3_GetMemorySize(runtime);
//NOTE: check size of uniformNames
{
ORCA_ASSERT(((char*)uniformNames >= (char*)_mem) && (((char*)uniformNames - (char*)_mem) < memorySize),
"parameter 'uniformNames' is out of bounds");
ORCA_ASSERT((char*)uniformNames + uniformCount * sizeof(u32) <= ((char*)_mem + memorySize),
"parameter 'uniformNames' overflows wasm memory");
}
//NOTE: check each individual uniformNames
mem_arena_scope scratch = mem_scratch_begin();
char** uniformNamesRaw = mem_arena_alloc_array(scratch.arena, char*, uniformCount);
for(int i=0; i<uniformCount; i++)
{
char* raw = ((char*)_mem + uniformNames[i]);
ORCA_ASSERT(raw >= (char*)_mem && (raw - (char*)_mem) < memorySize, "uniformName[%i] is out of bounds", i);
u64 len = orca_gles_check_cstring(runtime, raw);
ORCA_ASSERT(raw + len <= ((char*)_mem + memorySize), "uniformName[%i] overflows wasm memory", i);
uniformNamesRaw[i] = raw;
}
//NOTE: check size of uniformIndices
{
ORCA_ASSERT(((char*)uniformIndices >= (char*)_mem) && (((char*)uniformIndices - (char*)_mem) < memorySize),
"parameter 'uniformIndices' is out of bounds");
ORCA_ASSERT((char*)uniformIndices + uniformCount * sizeof(GLuint) <= ((char*)_mem + memorySize),
"parameter 'uniformIndices' overflows wasm memory");
}
glGetUniformIndices(program, uniformCount, (const GLchar* const*)uniformNamesRaw, uniformIndices);
mem_scratch_end(scratch);
return(0);
}
typedef struct orca_gl_getstring_entry
{
u32 offset;
u32 len;
} orca_gl_getstring_entry;
GLenum ORCA_GL_GETSTRING_NAMES[] = {
GL_EXTENSIONS,
GL_VENDOR,
GL_RENDERER,
GL_VERSION,
GL_SHADING_LANGUAGE_VERSION
};
enum {
ORCA_GL_GETSTRING_ENTRY_COUNT = sizeof(ORCA_GL_GETSTRING_NAMES)/sizeof(GLenum)
};
typedef struct orca_gl_getstring_info
{
bool init;
orca_gl_getstring_entry entries[ORCA_GL_GETSTRING_ENTRY_COUNT];
u32 indexedEntryCount;
orca_gl_getstring_entry* indexedEntries;
} orca_gl_getstring_info;
orca_gl_getstring_info __orcaGLGetStringInfo = {0};
void orca_gl_getstring_init(orca_gl_getstring_info* info, char* memory)
{
u32 totalSize = 0;
const char* strings[ORCA_GL_GETSTRING_ENTRY_COUNT] = {0};
for(int i=0; i<ORCA_GL_GETSTRING_ENTRY_COUNT; i++)
{
strings[i] = (const char*)glGetString(ORCA_GL_GETSTRING_NAMES[i]);
if(strings[i])
{
info->entries[i].len = strlen(strings[i]) + 1;
totalSize += info->entries[i].len;
}
}
glGetIntegerv(GL_NUM_EXTENSIONS, (GLint*)&info->indexedEntryCount);
mem_arena_scope scratch = mem_scratch_begin();
const char** extensions = mem_arena_alloc(scratch.arena, info->indexedEntryCount);
//NOTE: we will hold this until program terminates
info->indexedEntries = malloc_array(orca_gl_getstring_entry, info->indexedEntryCount);
for(int i=0; i<info->indexedEntryCount; i++)
{
extensions[i] = (const char*)glGetStringi(GL_EXTENSIONS, i);
if(extensions[i])
{
info->indexedEntries[i].len = strlen(extensions[i])+1;
totalSize += info->indexedEntries[i].len;
}
}
u32 wasmIndex = orca_mem_grow(totalSize);
for(int i=0; i<ORCA_GL_GETSTRING_ENTRY_COUNT; i++)
{
if(strings[i])
{
info->entries[i].offset = wasmIndex;
memcpy(memory + wasmIndex, strings[i], info->entries[i].len);
wasmIndex += info->entries[i].len;
}
}
for(int i=0; i<info->indexedEntryCount; i++)
{
if(extensions[i])
{
info->indexedEntries[i].offset = wasmIndex;
memcpy(memory + wasmIndex, extensions[i], info->indexedEntries[i].len);
wasmIndex += info->indexedEntries[i].len;
}
}
mem_scratch_end(scratch);
info->init = true;
}
const void* glGetString_stub(IM3Runtime runtime, IM3ImportContext _ctx, uint64_t* _sp, void* _mem)
{
if(!__orcaGLGetStringInfo.init)
{
uint32_t memorySize = 0;
char* memory = (char*)m3_GetMemory(runtime, &memorySize, 0);
orca_gl_getstring_init(&__orcaGLGetStringInfo, memory);
}
GLenum name = (GLenum)*(i32*)&_sp[1];
*(u32*)&_sp[0] = 0;
for(int i=0; i<ORCA_GL_GETSTRING_ENTRY_COUNT; i++)
{
if(name == ORCA_GL_GETSTRING_NAMES[i])
{
*(u32*)&_sp[0] = __orcaGLGetStringInfo.entries[i].offset;
break;
}
}
//NOTE: we still call glGetString so that it can set errors if name is incorrect
glGetString(name);
return(0);
}
const void* glGetStringi_stub(IM3Runtime runtime, IM3ImportContext _ctx, uint64_t* _sp, void* _mem)
{
if(!__orcaGLGetStringInfo.init)
{
uint32_t memorySize = 0;
char* memory = (char*)m3_GetMemory(runtime, &memorySize, 0);
orca_gl_getstring_init(&__orcaGLGetStringInfo, memory);
}
GLenum name = (GLenum)*(i32*)&_sp[1];
GLuint index = (GLuint)*(i32*)&_sp[2];
*(u32*)&_sp[0] = 0;
if(name == GL_EXTENSIONS && index < __orcaGLGetStringInfo.indexedEntryCount)
{
*(u32*)&_sp[0] = __orcaGLGetStringInfo.indexedEntries[index].offset;
}
//NOTE: we still call glGetString so that it can set errors if name is incorrect
glGetStringi(name, index);
return(0);
}
int manual_link_gles_api(IM3Module module)
{
#define M3_LINK_ERROR_HANDLING(name) \
if(res != m3Err_none && res != m3Err_functionLookupFailed) \
{ \
log_error("Couldn't link function " #name " (%s)\n", res); \
ret = -1; \
}
M3Result res;
int ret = 0;
res = m3_LinkRawFunction(module, "*", "glShaderSource", "v(iiii)", glShaderSource_stub);
M3_LINK_ERROR_HANDLING(glShaderSource)
res = m3_LinkRawFunction(module, "*", "glGetUniformIndices", "v(iiii)", glGetUniformIndices_stub);
M3_LINK_ERROR_HANDLING(glGetUniformIndices)
res = m3_LinkRawFunction(module, "*", "glGetVertexAttribPointerv", "v(iii)", glGetVertexAttribPointerv_stub);
M3_LINK_ERROR_HANDLING(glGetVertexAttribPointerv)
res = m3_LinkRawFunction(module, "*", "glGetString", "i(i)", glGetString_stub);
M3_LINK_ERROR_HANDLING(glGetGetString)
res = m3_LinkRawFunction(module, "*", "glGetStringi", "i(ii)", glGetStringi_stub);
M3_LINK_ERROR_HANDLING(glGetStringi)
res = m3_LinkRawFunction(module, "*", "glVertexAttribPointer", "v(iiiiii)", glVertexAttribPointer_stub);
M3_LINK_ERROR_HANDLING(glVertexAttribPointer)
res = m3_LinkRawFunction(module, "*", "glVertexAttribIPointer", "v(iiiii)", glVertexAttribIPointer_stub);
M3_LINK_ERROR_HANDLING(glVertexAttribIPointer)
#undef M3_LINK_ERROR_HANDLING
return(ret);
}