mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
[Feat] (MG_State/MG_Impl): ARB_vertex_attrib_binding + ARB_multi_bind state model
Add a separate binding-point model to VertexArrayObject with eager resolution into the flat per-attribute view backends already consume. Implements glBindVertexBuffer(s), glVertexAttrib(I)Format, glVertexAttribBinding, glVertexBindingDivisor and the DSA variants (glVertexArrayAttribBinding, glVertexArrayBindingDivisor, glVertexArrayVertexBuffers), fixing glVertexArrayVertexBuffer which previously conflated binding index with attribute index. Multi-bind (glBindBuffersBase/Range) loops over the single-bind entry points. Needed by Flywheel's indirect backend (GlVertexArrayDSA setup path). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1444,4 +1444,23 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) {
|
||||
BindBufferRange_State(target, index, buffer, offset, size);
|
||||
}
|
||||
|
||||
// ARB_multi_bind: defined by the spec as equivalent to a loop over the single-bind entry
|
||||
// points (with buffer 0 resetting the binding point).
|
||||
void BindBuffersBase(GLenum target, GLuint first, GLsizei count, const GLuint* buffers) {
|
||||
for (GLsizei i = 0; i < count; ++i) {
|
||||
BindBufferBase_State(target, first + i, buffers ? buffers[i] : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void BindBuffersRange(GLenum target, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets,
|
||||
const GLsizeiptr* sizes) {
|
||||
for (GLsizei i = 0; i < count; ++i) {
|
||||
if (!buffers || buffers[i] == 0) {
|
||||
BindBufferBase_State(target, first + i, 0);
|
||||
} else {
|
||||
BindBufferRange_State(target, first + i, buffers[i], offsets ? offsets[i] : 0, sizes ? sizes[i] : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -45,5 +45,8 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
void GenBuffers(GLsizei n, GLuint* buffers);
|
||||
void BindBufferBase(GLenum target, GLuint index, GLuint buffer);
|
||||
void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
|
||||
void BindBuffersBase(GLenum target, GLuint first, GLsizei count, const GLuint* buffers);
|
||||
void BindBuffersRange(GLenum target, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets,
|
||||
const GLsizeiptr* sizes);
|
||||
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -376,11 +376,11 @@ DECLARE_GL_FUNCTION_HEAD(void, GetMultisamplefv, GLenum pname, GLuint index, GLf
|
||||
DECLARE_GL_FUNCTION_HEAD(void, SampleMaski, GLuint maskNumber, GLbitfield mask) DECLARE_GL_FUNCTION_END_NO_RETURN(void, SampleMaski, maskNumber, mask)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, GetTexLevelParameteriv, GLenum target, GLint level, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTexLevelParameteriv, target, level, pname, params)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, GetTexLevelParameterfv, GLenum target, GLint level, GLenum pname, GLfloat* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTexLevelParameterfv, target, level, pname, params)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindVertexBuffer, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindVertexBuffer, bindingindex, buffer, offset, stride)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribFormat, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribFormat, attribindex, size, type, normalized, relativeoffset)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribIFormat, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribIFormat, attribindex, size, type, relativeoffset)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribBinding, GLuint attribindex, GLuint bindingindex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribBinding, attribindex, bindingindex)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexBindingDivisor, GLuint bindingindex, GLuint divisor) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexBindingDivisor, bindingindex, divisor)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, BindVertexBuffer, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindVertexBuffer, bindingindex, buffer, offset, stride)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, VertexAttribFormat, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttribFormat, attribindex, size, type, normalized, relativeoffset)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, VertexAttribIFormat, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttribIFormat, attribindex, size, type, relativeoffset)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, VertexAttribBinding, GLuint attribindex, GLuint bindingindex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttribBinding, attribindex, bindingindex)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, VertexBindingDivisor, GLuint bindingindex, GLuint divisor) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexBindingDivisor, bindingindex, divisor)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlendBarrier) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlendBarrier)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, CopyImageSubData, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CopyImageSubData, srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, DebugMessageControl, GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DebugMessageControl, source, type, severity, count, ids, enabled)
|
||||
@@ -1007,12 +1007,12 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribLFormat, GLuint attribindex, GLi
|
||||
DECLARE_GL_FUNCTION_HEAD(void, BufferStorage, GLenum target, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BufferStorage, target, size, data, flags)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearTexImage, GLuint texture, GLint level, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearTexImage, texture, level, format, type, data)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearTexSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearTexSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindBuffersBase, GLenum target, GLuint first, GLsizei count, const GLuint* buffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindBuffersBase, target, first, count, buffers)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindBuffersRange, GLenum target, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets, const GLsizeiptr* sizes) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindBuffersRange, target, first, count, buffers, offsets, sizes)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, BindBuffersBase, GLenum target, GLuint first, GLsizei count, const GLuint* buffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindBuffersBase, target, first, count, buffers)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, BindBuffersRange, GLenum target, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets, const GLsizeiptr* sizes) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindBuffersRange, target, first, count, buffers, offsets, sizes)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindTextures, GLuint first, GLsizei count, const GLuint* textures) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindTextures, first, count, textures)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, BindSamplers, GLuint first, GLsizei count, const GLuint* samplers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindSamplers, first, count, samplers)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindImageTextures, GLuint first, GLsizei count, const GLuint* textures) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindImageTextures, first, count, textures)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindVertexBuffers, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets, const GLsizei* strides) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindVertexBuffers, first, count, buffers, offsets, strides)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, BindVertexBuffers, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets, const GLsizei* strides) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindVertexBuffers, first, count, buffers, offsets, strides)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClipControl, GLenum origin, GLenum depth) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClipControl, origin, depth)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateTransformFeedbacks, GLsizei n, GLuint* ids) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateTransformFeedbacks, n, ids)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TransformFeedbackBufferBase, GLuint xfb, GLuint index, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TransformFeedbackBufferBase, xfb, index, buffer)
|
||||
@@ -1093,12 +1093,12 @@ DECLARE_GL_FUNCTION_HEAD(void, DisableVertexArrayAttrib, GLuint vaobj, GLuint in
|
||||
DECLARE_GL_FUNCTION_HEAD(void, EnableVertexArrayAttrib, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, EnableVertexArrayAttrib, vaobj, index)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayElementBuffer, GLuint vaobj, GLuint buffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayElementBuffer, vaobj, buffer)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayVertexBuffer, GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayVertexBuffer, vaobj, bindingindex, buffer, offset, stride)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexBuffers, GLuint vaobj, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets, const GLsizei* strides) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayVertexBuffers, vaobj, first, count, buffers, offsets, strides)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribBinding, GLuint vaobj, GLuint attribindex, GLuint bindingindex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribBinding, vaobj, attribindex, bindingindex)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayVertexBuffers, GLuint vaobj, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets, const GLsizei* strides) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayVertexBuffers, vaobj, first, count, buffers, offsets, strides)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayAttribBinding, GLuint vaobj, GLuint attribindex, GLuint bindingindex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayAttribBinding, vaobj, attribindex, bindingindex)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayAttribFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayAttribFormat, vaobj, attribindex, size, type, normalized, relativeoffset)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayAttribIFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayAttribIFormat, vaobj, attribindex, size, type, relativeoffset)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribLFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribLFormat, vaobj, attribindex, size, type, relativeoffset)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayBindingDivisor, GLuint vaobj, GLuint bindingindex, GLuint divisor) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayBindingDivisor, vaobj, bindingindex, divisor)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, VertexArrayBindingDivisor, GLuint vaobj, GLuint bindingindex, GLuint divisor) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayBindingDivisor, vaobj, bindingindex, divisor)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayiv, GLuint vaobj, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayiv, vaobj, pname, param)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIndexediv, GLuint vaobj, GLuint index, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayIndexediv, vaobj, index, pname, param)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIndexed64iv, GLuint vaobj, GLuint index, GLenum pname, GLint64* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayIndexed64iv, vaobj, index, pname, param)
|
||||
|
||||
@@ -47,6 +47,27 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
return pname == GL_CURRENT_VERTEX_ATTRIB;
|
||||
}
|
||||
|
||||
static bool ValidateVertexBindingIndex(GLuint bindingindex, const char* funcName) {
|
||||
if (bindingindex >= MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIB_BINDINGS) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", funcName,
|
||||
"bindingindex exceeds GL_MAX_VERTEX_ATTRIB_BINDINGS."));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static SharedPtr<MG_State::GLState::VertexArrayObject> GetBoundVertexArrayOrError(const char* funcName) {
|
||||
auto& vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!vao) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", funcName, "No vertex array object is bound."));
|
||||
}
|
||||
return vao;
|
||||
}
|
||||
|
||||
static bool ValidateVertexAttribPname(GLenum pname) {
|
||||
switch (pname) {
|
||||
case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
|
||||
@@ -260,51 +281,83 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
vao->GetIndexBufferBindingSlot().Bind(bufferObject);
|
||||
}
|
||||
|
||||
static void VertexBufferBinding_State(const SharedPtr<MG_State::GLState::VertexArrayObject>& vao,
|
||||
GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride,
|
||||
const char* caller) {
|
||||
if (!ValidateVertexBindingIndex(bindingindex, caller)) return;
|
||||
if (offset < 0 || stride < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "offset and stride must be non-negative."));
|
||||
return;
|
||||
}
|
||||
auto bufferObject = GetVertexArrayBufferObject_State(buffer, caller);
|
||||
if (buffer != 0 && !bufferObject) return;
|
||||
|
||||
vao->SetBindingBuffer(bindingindex, bufferObject, static_cast<SizeT>(offset), stride);
|
||||
}
|
||||
|
||||
void VertexArrayVertexBuffer_State(GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset,
|
||||
GLsizei stride) {
|
||||
auto vao = GetNamedVertexArrayObject_State(vaobj, "VertexArrayVertexBuffer_State");
|
||||
if (!vao) return;
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(bindingindex)) return;
|
||||
if (offset < 0 || stride < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "VertexArrayVertexBuffer_State",
|
||||
"offset and stride must be non-negative."));
|
||||
return;
|
||||
}
|
||||
auto bufferObject = GetVertexArrayBufferObject_State(buffer, "VertexArrayVertexBuffer_State");
|
||||
if (buffer != 0 && !bufferObject) return;
|
||||
VertexBufferBinding_State(vao, bindingindex, buffer, offset, stride, "VertexArrayVertexBuffer_State");
|
||||
}
|
||||
|
||||
const auto& attr = vao->GetAttribute(bindingindex);
|
||||
vao->SetAttributeFormat(bindingindex, attr.Size, attr.Type, attr.Normalized, stride, static_cast<SizeT>(offset),
|
||||
attr.IsInteger);
|
||||
vao->BindAttributeBuffer(bindingindex, bufferObject);
|
||||
void VertexArrayVertexBuffers_State(GLuint vaobj, GLuint first, GLsizei count, const GLuint* buffers,
|
||||
const GLintptr* offsets, const GLsizei* strides) {
|
||||
auto vao = GetNamedVertexArrayObject_State(vaobj, "VertexArrayVertexBuffers_State");
|
||||
if (!vao) return;
|
||||
for (GLsizei i = 0; i < count; ++i) {
|
||||
if (!buffers) {
|
||||
VertexBufferBinding_State(vao, first + i, 0, 0, 16, "VertexArrayVertexBuffers_State");
|
||||
} else {
|
||||
VertexBufferBinding_State(vao, first + i, buffers[i], offsets ? offsets[i] : 0,
|
||||
strides ? strides[i] : 16, "VertexArrayVertexBuffers_State");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void VertexAttribFormatSeparate_State(const SharedPtr<MG_State::GLState::VertexArrayObject>& vao,
|
||||
GLuint attribindex, GLint size, GLenum type, GLboolean normalized,
|
||||
GLuint relativeoffset, Bool isInteger, const char* caller) {
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(attribindex)) return;
|
||||
|
||||
DataType dataType = MG_Util::ConvertGLEnumToDataType(type);
|
||||
if (!VertexArrayImpl::ValidateVertexAttribPointerParams(attribindex, size, dataType, 0)) return;
|
||||
|
||||
vao->SetAttributeFormatSeparate(attribindex, size, dataType, normalized, isInteger, relativeoffset);
|
||||
}
|
||||
|
||||
void VertexArrayAttribFormat_State(GLuint vaobj, GLuint attribindex, GLint size, GLenum type,
|
||||
GLboolean normalized, GLuint relativeoffset) {
|
||||
auto vao = GetNamedVertexArrayObject_State(vaobj, "VertexArrayAttribFormat_State");
|
||||
if (!vao) return;
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(attribindex)) return;
|
||||
|
||||
DataType dataType = MG_Util::ConvertGLEnumToDataType(type);
|
||||
const auto& attr = vao->GetAttribute(attribindex);
|
||||
if (!VertexArrayImpl::ValidateVertexAttribPointerParams(attribindex, size, dataType, attr.Stride)) return;
|
||||
|
||||
vao->SetAttributeFormat(attribindex, size, dataType, normalized, attr.Stride, relativeoffset, false);
|
||||
VertexAttribFormatSeparate_State(vao, attribindex, size, type, normalized, relativeoffset, false,
|
||||
"VertexArrayAttribFormat_State");
|
||||
}
|
||||
|
||||
void VertexArrayAttribIFormat_State(GLuint vaobj, GLuint attribindex, GLint size, GLenum type,
|
||||
GLuint relativeoffset) {
|
||||
auto vao = GetNamedVertexArrayObject_State(vaobj, "VertexArrayAttribIFormat_State");
|
||||
if (!vao) return;
|
||||
VertexAttribFormatSeparate_State(vao, attribindex, size, type, GL_FALSE, relativeoffset, true,
|
||||
"VertexArrayAttribIFormat_State");
|
||||
}
|
||||
|
||||
void VertexArrayAttribBinding_State(GLuint vaobj, GLuint attribindex, GLuint bindingindex) {
|
||||
auto vao = GetNamedVertexArrayObject_State(vaobj, "VertexArrayAttribBinding_State");
|
||||
if (!vao) return;
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(attribindex)) return;
|
||||
if (!ValidateVertexBindingIndex(bindingindex, "VertexArrayAttribBinding_State")) return;
|
||||
vao->SetAttributeBinding(attribindex, bindingindex);
|
||||
}
|
||||
|
||||
DataType dataType = MG_Util::ConvertGLEnumToDataType(type);
|
||||
const auto& attr = vao->GetAttribute(attribindex);
|
||||
if (!VertexArrayImpl::ValidateVertexAttribPointerParams(attribindex, size, dataType, attr.Stride)) return;
|
||||
|
||||
vao->SetAttributeFormat(attribindex, size, dataType, false, attr.Stride, relativeoffset, true);
|
||||
void VertexArrayBindingDivisor_State(GLuint vaobj, GLuint bindingindex, GLuint divisor) {
|
||||
auto vao = GetNamedVertexArrayObject_State(vaobj, "VertexArrayBindingDivisor_State");
|
||||
if (!vao) return;
|
||||
if (!ValidateVertexBindingIndex(bindingindex, "VertexArrayBindingDivisor_State")) return;
|
||||
vao->SetBindingDivisor(bindingindex, divisor);
|
||||
}
|
||||
|
||||
GLboolean IsVertexArray_State(GLuint array) {
|
||||
@@ -640,6 +693,68 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
VertexArrayAttribIFormat_State(vaobj, attribindex, size, type, relativeoffset);
|
||||
}
|
||||
|
||||
void VertexArrayAttribBinding(GLuint vaobj, GLuint attribindex, GLuint bindingindex) {
|
||||
VertexArrayAttribBinding_State(vaobj, attribindex, bindingindex);
|
||||
}
|
||||
|
||||
void VertexArrayBindingDivisor(GLuint vaobj, GLuint bindingindex, GLuint divisor) {
|
||||
VertexArrayBindingDivisor_State(vaobj, bindingindex, divisor);
|
||||
}
|
||||
|
||||
void VertexArrayVertexBuffers(GLuint vaobj, GLuint first, GLsizei count, const GLuint* buffers,
|
||||
const GLintptr* offsets, const GLsizei* strides) {
|
||||
VertexArrayVertexBuffers_State(vaobj, first, count, buffers, offsets, strides);
|
||||
}
|
||||
|
||||
void BindVertexBuffer(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) {
|
||||
auto vao = GetBoundVertexArrayOrError("BindVertexBuffer");
|
||||
if (!vao) return;
|
||||
VertexBufferBinding_State(vao, bindingindex, buffer, offset, stride, "BindVertexBuffer");
|
||||
}
|
||||
|
||||
void BindVertexBuffers(GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets,
|
||||
const GLsizei* strides) {
|
||||
auto vao = GetBoundVertexArrayOrError("BindVertexBuffers");
|
||||
if (!vao) return;
|
||||
for (GLsizei i = 0; i < count; ++i) {
|
||||
if (!buffers) {
|
||||
VertexBufferBinding_State(vao, first + i, 0, 0, 16, "BindVertexBuffers");
|
||||
} else {
|
||||
VertexBufferBinding_State(vao, first + i, buffers[i], offsets ? offsets[i] : 0,
|
||||
strides ? strides[i] : 16, "BindVertexBuffers");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VertexAttribFormat(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset) {
|
||||
auto vao = GetBoundVertexArrayOrError("VertexAttribFormat");
|
||||
if (!vao) return;
|
||||
VertexAttribFormatSeparate_State(vao, attribindex, size, type, normalized, relativeoffset, false,
|
||||
"VertexAttribFormat");
|
||||
}
|
||||
|
||||
void VertexAttribIFormat(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) {
|
||||
auto vao = GetBoundVertexArrayOrError("VertexAttribIFormat");
|
||||
if (!vao) return;
|
||||
VertexAttribFormatSeparate_State(vao, attribindex, size, type, GL_FALSE, relativeoffset, true,
|
||||
"VertexAttribIFormat");
|
||||
}
|
||||
|
||||
void VertexAttribBinding(GLuint attribindex, GLuint bindingindex) {
|
||||
auto vao = GetBoundVertexArrayOrError("VertexAttribBinding");
|
||||
if (!vao) return;
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(attribindex)) return;
|
||||
if (!ValidateVertexBindingIndex(bindingindex, "VertexAttribBinding")) return;
|
||||
vao->SetAttributeBinding(attribindex, bindingindex);
|
||||
}
|
||||
|
||||
void VertexBindingDivisor(GLuint bindingindex, GLuint divisor) {
|
||||
auto vao = GetBoundVertexArrayOrError("VertexBindingDivisor");
|
||||
if (!vao) return;
|
||||
if (!ValidateVertexBindingIndex(bindingindex, "VertexBindingDivisor")) return;
|
||||
vao->SetBindingDivisor(bindingindex, divisor);
|
||||
}
|
||||
|
||||
void VertexAttribDivisor(GLuint index, GLuint divisor) {
|
||||
VertexAttribDivisor_State(index, divisor);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,17 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
void VertexArrayAttribFormat(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized,
|
||||
GLuint relativeoffset);
|
||||
void VertexArrayAttribIFormat(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
|
||||
void VertexArrayAttribBinding(GLuint vaobj, GLuint attribindex, GLuint bindingindex);
|
||||
void VertexArrayBindingDivisor(GLuint vaobj, GLuint bindingindex, GLuint divisor);
|
||||
void VertexArrayVertexBuffers(GLuint vaobj, GLuint first, GLsizei count, const GLuint* buffers,
|
||||
const GLintptr* offsets, const GLsizei* strides);
|
||||
void BindVertexBuffer(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
|
||||
void BindVertexBuffers(GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets,
|
||||
const GLsizei* strides);
|
||||
void VertexAttribFormat(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
|
||||
void VertexAttribIFormat(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
|
||||
void VertexAttribBinding(GLuint attribindex, GLuint bindingindex);
|
||||
void VertexBindingDivisor(GLuint bindingindex, GLuint divisor);
|
||||
void VertexAttribDivisor(GLuint index, GLuint divisor);
|
||||
GLboolean IsVertexArray(GLuint array);
|
||||
void DisableVertexAttribArray(GLuint index);
|
||||
|
||||
@@ -51,6 +51,9 @@ namespace MobileGL::MG_State::GLState {
|
||||
SizeT offset, Bool isInteger) {
|
||||
if (index >= MAX_VERTEX_ATTRIBS) return;
|
||||
|
||||
// The classic pointer-style API takes back full ownership of the resolved fields.
|
||||
m_attributeUsesBindingModel[index] = false;
|
||||
|
||||
if (m_attributes[index].Size == size && m_attributes[index].Type == type &&
|
||||
m_attributes[index].Normalized == normalized && m_attributes[index].Stride == stride &&
|
||||
m_attributes[index].Offset == offset && m_attributes[index].IsInteger == isInteger) {
|
||||
@@ -116,6 +119,91 @@ namespace MobileGL::MG_State::GLState {
|
||||
return m_attributes[index].Divisor;
|
||||
}
|
||||
|
||||
void VertexArrayObject::ResolveAttributeFromBinding(Uint attribIndex) {
|
||||
if (attribIndex >= MAX_VERTEX_ATTRIBS) return;
|
||||
if (!m_attributeUsesBindingModel[attribIndex]) return;
|
||||
|
||||
const Uint bindingIndex = m_attributeBindingIndex[attribIndex];
|
||||
if (bindingIndex >= MAX_VERTEX_ATTRIB_BINDINGS) return;
|
||||
const auto& binding = m_bindingPoints[bindingIndex];
|
||||
|
||||
auto& attr = m_attributes[attribIndex];
|
||||
|
||||
const SizeT resolvedOffset = binding.Offset + m_attributeRelativeOffset[attribIndex];
|
||||
if (attr.Stride != binding.Stride || attr.Offset != resolvedOffset || attr.Divisor != binding.Divisor) {
|
||||
attr.Stride = binding.Stride;
|
||||
attr.Offset = resolvedOffset;
|
||||
attr.Divisor = binding.Divisor;
|
||||
BumpAttributeFormatVersion(attribIndex);
|
||||
}
|
||||
|
||||
if (attr.Buffer != binding.Buffer) {
|
||||
attr.Buffer = binding.Buffer;
|
||||
BumpAttributeBufferVersion(attribIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void VertexArrayObject::SetBindingBuffer(Uint bindingIndex, const SharedPtr<BufferObject>& buffer, SizeT offset,
|
||||
int stride) {
|
||||
if (bindingIndex >= MAX_VERTEX_ATTRIB_BINDINGS) return;
|
||||
|
||||
auto& binding = m_bindingPoints[bindingIndex];
|
||||
binding.Buffer = buffer;
|
||||
binding.Offset = offset;
|
||||
binding.Stride = stride;
|
||||
|
||||
for (Uint attribIndex = 0; attribIndex < MAX_VERTEX_ATTRIBS; ++attribIndex) {
|
||||
if (m_attributeBindingIndex[attribIndex] == bindingIndex) {
|
||||
// Binding a vertex buffer to a binding point adopts every attribute currently
|
||||
// mapped to that binding point into the binding model (the default mapping is
|
||||
// attribute i -> binding i, which matches the GL 4.3 rules for state mixing).
|
||||
m_attributeUsesBindingModel[attribIndex] = true;
|
||||
ResolveAttributeFromBinding(attribIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VertexArrayObject::SetBindingDivisor(Uint bindingIndex, Uint divisor) {
|
||||
if (bindingIndex >= MAX_VERTEX_ATTRIB_BINDINGS) return;
|
||||
|
||||
m_bindingPoints[bindingIndex].Divisor = divisor;
|
||||
|
||||
for (Uint attribIndex = 0; attribIndex < MAX_VERTEX_ATTRIBS; ++attribIndex) {
|
||||
if (m_attributeBindingIndex[attribIndex] == bindingIndex && m_attributeUsesBindingModel[attribIndex]) {
|
||||
ResolveAttributeFromBinding(attribIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VertexArrayObject::SetAttributeBinding(Uint attribIndex, Uint bindingIndex) {
|
||||
if (attribIndex >= MAX_VERTEX_ATTRIBS) return;
|
||||
if (bindingIndex >= MAX_VERTEX_ATTRIB_BINDINGS) return;
|
||||
|
||||
m_attributeBindingIndex[attribIndex] = bindingIndex;
|
||||
m_attributeUsesBindingModel[attribIndex] = true;
|
||||
ResolveAttributeFromBinding(attribIndex);
|
||||
}
|
||||
|
||||
void VertexArrayObject::SetAttributeFormatSeparate(Uint attribIndex, int size, DataType type, Bool normalized,
|
||||
Bool isInteger, Uint relativeOffset) {
|
||||
if (attribIndex >= MAX_VERTEX_ATTRIBS) return;
|
||||
if (size < 1 || size > 4) return;
|
||||
|
||||
auto& attr = m_attributes[attribIndex];
|
||||
if (attr.Size != size || attr.Type != type || attr.Normalized != normalized || attr.IsInteger != isInteger ||
|
||||
m_attributeRelativeOffset[attribIndex] != relativeOffset) {
|
||||
attr.Size = size;
|
||||
attr.Type = type;
|
||||
attr.Normalized = normalized;
|
||||
attr.IsInteger = isInteger;
|
||||
m_attributeRelativeOffset[attribIndex] = relativeOffset;
|
||||
BumpAttributeFormatVersion(attribIndex);
|
||||
}
|
||||
|
||||
m_attributeUsesBindingModel[attribIndex] = true;
|
||||
ResolveAttributeFromBinding(attribIndex);
|
||||
}
|
||||
|
||||
void VertexArrayObject::BumpAttributeFormatVersion(Uint index) {
|
||||
if (index >= MAX_VERTEX_ATTRIBS) return;
|
||||
++m_attributeVersions[index].FormatVersion;
|
||||
|
||||
@@ -26,6 +26,16 @@ namespace MobileGL {
|
||||
SharedPtr<BufferObject> Buffer;
|
||||
};
|
||||
|
||||
// ARB_vertex_attrib_binding separate binding point. Attributes configured through the
|
||||
// binding-point API are resolved eagerly into the flat VertexAttribute view above, so
|
||||
// backends keep consuming resolved attributes and never see binding points.
|
||||
struct VertexBufferBindingPoint {
|
||||
SharedPtr<BufferObject> Buffer;
|
||||
SizeT Offset = 0;
|
||||
int Stride = 0;
|
||||
Uint Divisor = 0;
|
||||
};
|
||||
|
||||
struct VertexAttributeVersion {
|
||||
Uint16 FormatVersion = 0;
|
||||
Uint16 BufferVersion = 0;
|
||||
@@ -35,6 +45,7 @@ namespace MobileGL {
|
||||
class VertexArrayObject {
|
||||
public:
|
||||
static constexpr int MAX_VERTEX_ATTRIBS = 16;
|
||||
static constexpr int MAX_VERTEX_ATTRIB_BINDINGS = 16;
|
||||
|
||||
VertexArrayObject(Uint externIndex);
|
||||
|
||||
@@ -58,6 +69,15 @@ namespace MobileGL {
|
||||
void SetAttributeDivisor(Uint index, Uint divisor);
|
||||
Uint GetAttributeDivisor(Uint index) const;
|
||||
|
||||
// ARB_vertex_attrib_binding style state. Each mutation re-resolves the affected
|
||||
// attributes into the flat VertexAttribute view.
|
||||
void SetBindingBuffer(Uint bindingIndex, const SharedPtr<BufferObject>& buffer, SizeT offset,
|
||||
int stride);
|
||||
void SetBindingDivisor(Uint bindingIndex, Uint divisor);
|
||||
void SetAttributeBinding(Uint attribIndex, Uint bindingIndex);
|
||||
void SetAttributeFormatSeparate(Uint attribIndex, int size, DataType type, Bool normalized,
|
||||
Bool isInteger, Uint relativeOffset);
|
||||
|
||||
const VertexAttributeVersion& GetAttributeVersion(Uint index) const;
|
||||
const Array<VertexAttributeVersion, MAX_VERTEX_ATTRIBS>& GetAllAttributeVersions() const;
|
||||
|
||||
@@ -65,11 +85,21 @@ namespace MobileGL {
|
||||
void BumpAttributeFormatVersion(Uint index);
|
||||
void BumpAttributeBufferVersion(Uint index);
|
||||
void BumpAttributeSwitchVersion(Uint index);
|
||||
void ResolveAttributeFromBinding(Uint attribIndex);
|
||||
|
||||
const Uint m_externalIndex = 0;
|
||||
Array<VertexAttribute, MAX_VERTEX_ATTRIBS> m_attributes;
|
||||
Array<VertexAttributeVersion, MAX_VERTEX_ATTRIBS> m_attributeVersions;
|
||||
BindingSlot<BufferObject> m_indexBufferBindingSlot;
|
||||
|
||||
Array<VertexBufferBindingPoint, MAX_VERTEX_ATTRIB_BINDINGS> m_bindingPoints;
|
||||
Array<Uint, MAX_VERTEX_ATTRIBS> m_attributeBindingIndex = {0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 11, 12, 13, 14, 15};
|
||||
Array<Uint, MAX_VERTEX_ATTRIBS> m_attributeRelativeOffset = {};
|
||||
// Set once an attribute (or its binding point) is touched through the
|
||||
// ARB_vertex_attrib_binding API; only such attributes are re-resolved, so the
|
||||
// classic glVertexAttribPointer path keeps its exact historical behavior.
|
||||
Array<Bool, MAX_VERTEX_ATTRIBS> m_attributeUsesBindingModel = {};
|
||||
};
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
|
||||
Reference in New Issue
Block a user