mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 20:58:31 +09:00
[Feat] (MG_Impl/VertexArray): implement client-side buffer
This commit is contained in:
@@ -863,6 +863,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#endif
|
||||
DrawSyncBit syncBit = DrawSyncBit::None;
|
||||
PrepareForDraw(syncBit);
|
||||
const auto& currentVAO = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (currentVAO) {
|
||||
const auto& backendVAOIt = VertexArrayImpl::g_backendVertexArrayObjects.find(currentVAO.get());
|
||||
if (backendVAOIt != VertexArrayImpl::g_backendVertexArrayObjects.end()) {
|
||||
backendVAOIt->second->SyncClientSideAttributesForDrawArrays(currentVAO, first, count);
|
||||
}
|
||||
}
|
||||
g_GLESFuncs.glDrawArrays(mode, first, count);
|
||||
}
|
||||
|
||||
|
||||
@@ -194,10 +194,34 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
} // namespace BufferImpl
|
||||
|
||||
namespace VertexArrayImpl {
|
||||
namespace {
|
||||
SizeT GetDataTypeSize(DataType type) {
|
||||
switch (type) {
|
||||
case DataType::Int8:
|
||||
case DataType::Uint8:
|
||||
return 1;
|
||||
case DataType::Int16:
|
||||
case DataType::Uint16:
|
||||
case DataType::Float16:
|
||||
return 2;
|
||||
case DataType::Int32:
|
||||
case DataType::Uint32:
|
||||
case DataType::Float32:
|
||||
case DataType::Fixed32:
|
||||
return 4;
|
||||
case DataType::Float64:
|
||||
return 8;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
BackendVertexArrayObject::BackendVertexArrayObject() {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
m_clientAttributeBufferIds.fill(0);
|
||||
g_GLESFuncs.glGenVertexArrays(1, &m_backendVAOId);
|
||||
if (m_backendVAOId == 0) {
|
||||
MGLOG_E("Failed to generate vertex array object.");
|
||||
@@ -207,6 +231,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
}
|
||||
|
||||
BackendVertexArrayObject::~BackendVertexArrayObject() {
|
||||
if (m_backendVAOId != 0) {
|
||||
g_GLESFuncs.glDeleteVertexArrays(1, &m_backendVAOId);
|
||||
m_backendVAOId = 0;
|
||||
}
|
||||
for (auto& bufferId : m_clientAttributeBufferIds) {
|
||||
if (bufferId != 0) {
|
||||
g_GLESFuncs.glDeleteBuffers(1, &bufferId);
|
||||
bufferId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BackendVertexArrayObject::Bind() const {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
@@ -312,6 +349,58 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
m_syncedAttributeVersions = allAttributeVersions;
|
||||
}
|
||||
|
||||
void BackendVertexArrayObject::SyncClientSideAttributesForDrawArrays(
|
||||
const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject, GLint first, GLsizei count) {
|
||||
if (!stateVAOObject || count <= 0 || first < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Bind();
|
||||
|
||||
const auto& allAttributes = stateVAOObject->GetAllAttributes();
|
||||
for (Uint attribIndex = 0; attribIndex < allAttributes.size(); ++attribIndex) {
|
||||
const auto& attrib = allAttributes[attribIndex];
|
||||
if (!attrib.Enabled || attrib.Buffer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto* clientData = reinterpret_cast<const Uint8*>(attrib.Offset);
|
||||
const SizeT componentSize = GetDataTypeSize(attrib.Type);
|
||||
if (!clientData || componentSize == 0 || attrib.Size <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const SizeT elementSize = componentSize * static_cast<SizeT>(attrib.Size);
|
||||
const SizeT stride = attrib.Stride > 0 ? static_cast<SizeT>(attrib.Stride) : elementSize;
|
||||
const SizeT uploadSize = static_cast<SizeT>(first + count - 1) * stride + elementSize;
|
||||
|
||||
auto& bufferId = m_clientAttributeBufferIds[attribIndex];
|
||||
if (bufferId == 0) {
|
||||
g_GLESFuncs.glGenBuffers(1, &bufferId);
|
||||
if (bufferId == 0) {
|
||||
MGLOG_E("Failed to create client-side vertex attribute upload buffer.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
g_GLESFuncs.glBindBuffer(GL_ARRAY_BUFFER, bufferId);
|
||||
g_GLESFuncs.glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(uploadSize), clientData,
|
||||
GL_STREAM_DRAW);
|
||||
|
||||
if (!attrib.IsInteger) {
|
||||
g_GLESFuncs.glVertexAttribPointer(
|
||||
attribIndex, attrib.Size, MG_Util::ConvertDataTypeToGLEnum(attrib.Type),
|
||||
attrib.Normalized ? GL_TRUE : GL_FALSE, static_cast<GLsizei>(stride), nullptr);
|
||||
} else {
|
||||
g_GLESFuncs.glVertexAttribIPointer(attribIndex, attrib.Size,
|
||||
MG_Util::ConvertDataTypeToGLEnum(attrib.Type),
|
||||
static_cast<GLsizei>(stride), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
BufferImpl::g_boundVertexBufferObject = nullptr;
|
||||
}
|
||||
|
||||
StateBackendObjectRegistry<MG_State::GLState::VertexArrayObject, BackendVertexArrayObject>
|
||||
g_backendVertexArrayObjects;
|
||||
} // namespace VertexArrayImpl
|
||||
|
||||
@@ -137,12 +137,16 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
class BackendVertexArrayObject {
|
||||
public:
|
||||
BackendVertexArrayObject();
|
||||
~BackendVertexArrayObject();
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject);
|
||||
void SyncClientSideAttributesForDrawArrays(
|
||||
const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject, GLint first, GLsizei count);
|
||||
Uint GetBackendVertexArrayId() const { return m_backendVAOId; }
|
||||
void Bind() const;
|
||||
|
||||
private:
|
||||
Uint m_backendVAOId = 0;
|
||||
Array<Uint, MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS> m_clientAttributeBufferIds;
|
||||
Bool m_isInitialized = false;
|
||||
Uint16 m_syncedIndexBufferVersion = 0;
|
||||
Array<MG_State::GLState::VertexAttributeVersion, MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS>
|
||||
|
||||
@@ -60,12 +60,6 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
|
||||
auto& vboSlot = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex);
|
||||
auto& vbo = vboSlot.GetBoundObject();
|
||||
if (!vbo) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "VertexAttribPointer_State",
|
||||
"No buffer is bound to GL_ARRAY_BUFFER."));
|
||||
return;
|
||||
}
|
||||
|
||||
auto offset = reinterpret_cast<SizeT>(pointer);
|
||||
|
||||
@@ -91,12 +85,6 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
|
||||
auto& vboSlot = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex);
|
||||
auto& vbo = vboSlot.GetBoundObject();
|
||||
if (!vbo) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "VertexAttribPointer_State",
|
||||
"No buffer is bound to GL_ARRAY_BUFFER."));
|
||||
return;
|
||||
}
|
||||
|
||||
SizeT offset = reinterpret_cast<SizeT>(pointer);
|
||||
|
||||
|
||||
@@ -363,6 +363,24 @@ TEST_F(GeneralVertexArrayTest, General_ElementArrayBufferBindingIsVaoLocalAndZer
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(GeneralVertexArrayTest, General_ClientSideVertexAttribPointerIsAccepted) {
|
||||
GLuint vao = CreateVAO();
|
||||
BindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
float vertices[] = {0.0f, 0.0f, 1.0f, 1.0f};
|
||||
VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices);
|
||||
EnableVertexAttribArray(0);
|
||||
|
||||
auto vaoObj = MG_State::pGLContext->GetVertexArrayObject(vao);
|
||||
ASSERT_NE(vaoObj, nullptr);
|
||||
|
||||
const auto& attr = vaoObj->GetAttribute(0);
|
||||
EXPECT_TRUE(attr.Enabled);
|
||||
EXPECT_EQ(attr.Buffer, nullptr);
|
||||
EXPECT_EQ(attr.Offset, reinterpret_cast<SizeT>(vertices));
|
||||
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(GeneralVertexArrayTest, General_IntegerAttributes) {
|
||||
GLuint vao = CreateVAO();
|
||||
GLuint vbo = CreateVBO(GL_ARRAY_BUFFER, 128);
|
||||
|
||||
Reference in New Issue
Block a user