//------------------------------------------------------------------------ // 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, ¶m); 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= (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= (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; ientries[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; iindexedEntryCount; 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; ientries[i].offset = wasmIndex; memcpy(memory + wasmIndex, strings[i], info->entries[i].len); wasmIndex += info->entries[i].len; } } for(int i=0; iindexedEntryCount; 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