mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-12 12:33:24 +09:00
[Feat] (MG_Impl, DirectGLES): advertise GL_ARB_get_program_binary with no binary format
glProgramParameteri is not core before GL 4.1, so in the 4.0 context the CTS runs it only exists through GL_ARB_get_program_binary or GL_ARB_separate_shader_objects. MobileGL advertised neither, so dEQP's loader left the entry point null - and KHR-GL40.api.coverage, which registers glProgramParameteri from GL 3.2 upwards, called straight through the null pointer and took the process down. GL_NUM_PROGRAM_BINARY_FORMATS was already 0, and the extension explicitly allows an implementation to support no binary format at all; that is the honest state of things here, since a MobileGL program is a glslang link plus a per-backend translation with no serialised form. So the extension is advertised for what it really provides: glProgramParameteri stores GL_PROGRAM_BINARY_RETRIEVABLE_HINT (reported back by glGetProgramiv alongside a GL_PROGRAM_BINARY_LENGTH of zero), glGetProgramBinary is the INVALID_OPERATION the spec requires when that length is zero, and glProgramBinary rejects every format with INVALID_ENUM and leaves the program's LINK_STATUS false. Applications that ask for a binary get the documented "no formats" answer and fall back, which is what they already had to do - only now they can ask.
This commit is contained in:
@@ -648,6 +648,13 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
case GL_PROGRAM_BINARY_LENGTH:
|
||||
// No program binary format is exposed, so a program never has a retrievable
|
||||
// binary and its length is zero (ARB_get_program_binary).
|
||||
*params = 0;
|
||||
break;
|
||||
case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
|
||||
*params = programObject->GetBinaryRetrievableHint() ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
|
||||
case GL_GEOMETRY_VERTICES_OUT:
|
||||
case GL_GEOMETRY_INPUT_TYPE:
|
||||
@@ -2258,6 +2265,65 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
ValidateProgram_State(program);
|
||||
}
|
||||
|
||||
// ARB_get_program_binary with no supported binary format (GL_NUM_PROGRAM_BINARY_FORMATS
|
||||
// is 0, which the extension explicitly allows). The three entry points below are what an
|
||||
// application - and dEQP's function loader - reach through the extension; without it
|
||||
// glProgramParameteri is not exposed in a 4.0 context at all.
|
||||
void ProgramParameteri(GLuint program, GLenum pname, GLint value) {
|
||||
auto& programObject = TryToGetProgramObject(program);
|
||||
if (!programObject) return;
|
||||
if (pname != GL_PROGRAM_BINARY_RETRIEVABLE_HINT) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "pname is not an accepted value."));
|
||||
return;
|
||||
}
|
||||
if (value != GL_TRUE && value != GL_FALSE) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "value must be GL_TRUE or GL_FALSE."));
|
||||
return;
|
||||
}
|
||||
programObject->SetBinaryRetrievableHint(value == GL_TRUE);
|
||||
}
|
||||
|
||||
void GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, void* binary) {
|
||||
(void)binaryFormat;
|
||||
(void)binary;
|
||||
auto& programObject = TryToGetProgramObject(program);
|
||||
if (!programObject) return;
|
||||
if (bufSize < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "bufSize must be non-negative."));
|
||||
return;
|
||||
}
|
||||
if (length) *length = 0;
|
||||
// GL_PROGRAM_BINARY_LENGTH is always zero here, which the spec makes an error to ask for.
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "The program has no retrievable binary."));
|
||||
}
|
||||
|
||||
void ProgramBinary(GLuint program, GLenum binaryFormat, const void* binary, GLsizei length) {
|
||||
(void)binaryFormat;
|
||||
(void)binary;
|
||||
auto& programObject = TryToGetProgramObject(program);
|
||||
if (!programObject) return;
|
||||
if (length < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "length must be non-negative."));
|
||||
return;
|
||||
}
|
||||
// No format is supported, so every binary is rejected - and the program's link status
|
||||
// has to read FALSE afterwards.
|
||||
programObject->MarkLinkFailedByProgramBinary();
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "binaryFormat is not a supported format."));
|
||||
}
|
||||
|
||||
void TransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode) {
|
||||
auto& programObject = TryToGetProgramObject(program);
|
||||
if (!programObject) return;
|
||||
|
||||
@@ -138,6 +138,9 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
GLint GetProgramResourceLocationIndex(GLuint program, GLenum programInterface, const GLchar* name);
|
||||
void ShaderStorageBlockBinding(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
|
||||
void ValidateProgram(GLuint program);
|
||||
void ProgramParameteri(GLuint program, GLenum pname, GLint value);
|
||||
void GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, void* binary);
|
||||
void ProgramBinary(GLuint program, GLenum binaryFormat, const void* binary, GLsizei length);
|
||||
void TransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode);
|
||||
void GetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size,
|
||||
GLenum* type, GLchar* name);
|
||||
|
||||
Reference in New Issue
Block a user