mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 12:48:32 +09:00
[Fix] (MG_Backend/DirectGLES, MG_Impl/Texture, MG_Test/Texture): fix Voxy base-instance and bound texStorage2D
This commit is contained in:
@@ -65,6 +65,34 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
Uint32 baseInstance = 0;
|
||||
};
|
||||
|
||||
struct DrawArraysIndirectCommand {
|
||||
Uint32 count = 0;
|
||||
Uint32 instanceCount = 0;
|
||||
Uint32 first = 0;
|
||||
Uint32 baseInstance = 0;
|
||||
};
|
||||
|
||||
const Uint8* ResolveIndirectCommandBytes(const void* indirect, SizeT requiredBytes, const char* label) {
|
||||
auto drawBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
|
||||
if (drawBuffer) {
|
||||
drawBuffer->MarkPersistentMappedRangeDirty();
|
||||
const auto drawData = drawBuffer->GetDataReadOnly();
|
||||
const SizeT commandOffset = reinterpret_cast<SizeT>(indirect);
|
||||
if (!drawData || commandOffset + requiredBytes > drawData->size()) {
|
||||
MGLOG_E("%s skipped: invalid GL_DRAW_INDIRECT_BUFFER binding or range", label);
|
||||
return nullptr;
|
||||
}
|
||||
return drawData->data() + commandOffset;
|
||||
}
|
||||
|
||||
if (!indirect) {
|
||||
MGLOG_E("%s skipped: indirect pointer is null", label);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<const Uint8*>(indirect);
|
||||
}
|
||||
|
||||
namespace DebugImpl {
|
||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
||||
void ErrorLopper::Loop(const std::function<void(GLenum)>& func) {
|
||||
@@ -1086,24 +1114,17 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return;
|
||||
}
|
||||
|
||||
auto drawBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
|
||||
if (!drawBuffer) {
|
||||
MGLOG_E("MultiDrawElementsIndirect skipped: no GL_DRAW_INDIRECT_BUFFER is bound");
|
||||
return;
|
||||
}
|
||||
drawBuffer->MarkPersistentMappedRangeDirty();
|
||||
const auto drawData = drawBuffer->GetDataReadOnly();
|
||||
const SizeT commandOffset = reinterpret_cast<SizeT>(indirect);
|
||||
const SizeT commandBytes = commandOffset + static_cast<SizeT>(stride) * static_cast<SizeT>(drawcount - 1) +
|
||||
sizeof(DrawElementsIndirectCommand);
|
||||
if (!drawData || commandBytes > drawData->size()) {
|
||||
MGLOG_E("MultiDrawElementsIndirect skipped: invalid GL_DRAW_INDIRECT_BUFFER binding or range");
|
||||
const auto* commandBytes = ResolveIndirectCommandBytes(
|
||||
indirect,
|
||||
static_cast<SizeT>(stride) * static_cast<SizeT>(drawcount - 1) + sizeof(DrawElementsIndirectCommand),
|
||||
"MultiDrawElementsIndirect");
|
||||
if (!commandBytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (GLsizei i = 0; i < drawcount; ++i) {
|
||||
DrawElementsIndirectCommand cmd{};
|
||||
std::memcpy(&cmd, drawData->data() + commandOffset + static_cast<SizeT>(i) * stride, sizeof(cmd));
|
||||
std::memcpy(&cmd, commandBytes + static_cast<SizeT>(i) * stride, sizeof(cmd));
|
||||
if (cmd.count == 0 || cmd.instanceCount == 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -1192,14 +1213,41 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER
|
||||
DebugImpl::OpenGLScopeMarker marker(__func__);
|
||||
#endif
|
||||
DrawSyncBit syncBit = DrawSyncBit::IndirectBuffer;
|
||||
if (drawcount <= 0) {
|
||||
return;
|
||||
}
|
||||
if (stride == 0) {
|
||||
stride = sizeof(DrawArraysIndirectCommand);
|
||||
}
|
||||
if (stride < static_cast<GLsizei>(sizeof(DrawArraysIndirectCommand))) {
|
||||
MGLOG_E("MultiDrawArraysIndirect skipped: stride %d is smaller than command size %zu",
|
||||
stride, sizeof(DrawArraysIndirectCommand));
|
||||
return;
|
||||
}
|
||||
|
||||
DrawSyncBit syncBit = DrawSyncBit::IndirectBuffer | DrawSyncBit::Instancing;
|
||||
PrepareForDraw(syncBit);
|
||||
|
||||
for (GLsizei i = 0; i < drawcount; ++i) {
|
||||
const GLvoid* cmd = reinterpret_cast<const GLvoid*>(reinterpret_cast<const uint8_t*>(indirect) +
|
||||
i * (stride ? stride : sizeof(GLsizei) * 4));
|
||||
g_GLESFuncs.glDrawArraysIndirect(mode, cmd);
|
||||
const auto* commandBytes = ResolveIndirectCommandBytes(
|
||||
indirect,
|
||||
static_cast<SizeT>(stride) * static_cast<SizeT>(drawcount - 1) + sizeof(DrawArraysIndirectCommand),
|
||||
"MultiDrawArraysIndirect");
|
||||
if (!commandBytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (GLsizei i = 0; i < drawcount; ++i) {
|
||||
DrawArraysIndirectCommand cmd{};
|
||||
std::memcpy(&cmd, commandBytes + static_cast<SizeT>(i) * stride, sizeof(cmd));
|
||||
if (cmd.count == 0 || cmd.instanceCount == 0) {
|
||||
continue;
|
||||
}
|
||||
SetCurrentBaseInstance(cmd.baseInstance);
|
||||
g_GLESFuncs.glDrawArraysInstanced(
|
||||
mode, static_cast<GLint>(cmd.first), static_cast<GLsizei>(cmd.count),
|
||||
static_cast<GLsizei>(cmd.instanceCount));
|
||||
}
|
||||
SetCurrentBaseInstance(0);
|
||||
}
|
||||
|
||||
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||
@@ -1217,8 +1265,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLint basevertex, GLuint baseinstance) {
|
||||
// Not supported in OpenGL ES
|
||||
MGLOG_W("DrawElementsInstancedBaseVertexBaseInstance is not supported in OpenGL ES.");
|
||||
DrawSyncBit syncBit = DrawSyncBit::IndexBuffer | DrawSyncBit::Instancing;
|
||||
PrepareForDraw(syncBit);
|
||||
SetCurrentBaseInstance(baseinstance);
|
||||
g_GLESFuncs.glDrawElementsInstancedBaseVertex(mode, count, type, indices, instancecount, basevertex);
|
||||
SetCurrentBaseInstance(0);
|
||||
}
|
||||
|
||||
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
@@ -1230,8 +1281,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLuint baseinstance) {
|
||||
// Not supported in OpenGL ES
|
||||
MGLOG_W("DrawElementsInstancedBaseInstance is not supported in OpenGL ES.");
|
||||
DrawSyncBit syncBit = DrawSyncBit::IndexBuffer | DrawSyncBit::Instancing;
|
||||
PrepareForDraw(syncBit);
|
||||
SetCurrentBaseInstance(baseinstance);
|
||||
g_GLESFuncs.glDrawElementsInstanced(mode, count, type, indices, instancecount);
|
||||
SetCurrentBaseInstance(0);
|
||||
}
|
||||
|
||||
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount) {
|
||||
@@ -1241,15 +1295,42 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
|
||||
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect) {
|
||||
DrawSyncBit syncBit = DrawSyncBit::IndexBuffer | DrawSyncBit::IndirectBuffer;
|
||||
DrawSyncBit syncBit = DrawSyncBit::IndexBuffer | DrawSyncBit::IndirectBuffer | DrawSyncBit::Instancing;
|
||||
PrepareForDraw(syncBit);
|
||||
g_GLESFuncs.glDrawElementsIndirect(mode, type, indirect);
|
||||
|
||||
const SizeT indexSize = MG_Util::GetGLTypeSize(type);
|
||||
if (indexSize == 0) {
|
||||
MGLOG_E("DrawElementsIndirect skipped: unsupported index type 0x%x", type);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* commandBytes =
|
||||
ResolveIndirectCommandBytes(indirect, sizeof(DrawElementsIndirectCommand), "DrawElementsIndirect");
|
||||
if (!commandBytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
DrawElementsIndirectCommand cmd{};
|
||||
std::memcpy(&cmd, commandBytes, sizeof(cmd));
|
||||
if (cmd.count == 0 || cmd.instanceCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetCurrentBaseInstance(cmd.baseInstance);
|
||||
const auto indexByteOffset = static_cast<SizeT>(cmd.firstIndex) * indexSize;
|
||||
g_GLESFuncs.glDrawElementsInstancedBaseVertex(
|
||||
mode, static_cast<GLsizei>(cmd.count), type, reinterpret_cast<const GLvoid*>(indexByteOffset),
|
||||
static_cast<GLsizei>(cmd.instanceCount), cmd.baseVertex);
|
||||
SetCurrentBaseInstance(0);
|
||||
}
|
||||
|
||||
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
||||
GLuint baseinstance) {
|
||||
// Not supported in OpenGL ES
|
||||
MGLOG_W("DrawArraysInstancedBaseInstance is not supported in OpenGL ES.");
|
||||
DrawSyncBit syncBit = DrawSyncBit::Instancing;
|
||||
PrepareForDraw(syncBit);
|
||||
SetCurrentBaseInstance(baseinstance);
|
||||
g_GLESFuncs.glDrawArraysInstanced(mode, first, count, instancecount);
|
||||
SetCurrentBaseInstance(0);
|
||||
}
|
||||
|
||||
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount) {
|
||||
@@ -1259,9 +1340,26 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
|
||||
void DrawArraysIndirect(GLenum mode, const void* indirect) {
|
||||
DrawSyncBit syncBit = DrawSyncBit::IndirectBuffer;
|
||||
DrawSyncBit syncBit = DrawSyncBit::IndirectBuffer | DrawSyncBit::Instancing;
|
||||
PrepareForDraw(syncBit);
|
||||
g_GLESFuncs.glDrawArraysIndirect(mode, indirect);
|
||||
|
||||
const auto* commandBytes =
|
||||
ResolveIndirectCommandBytes(indirect, sizeof(DrawArraysIndirectCommand), "DrawArraysIndirect");
|
||||
if (!commandBytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
DrawArraysIndirectCommand cmd{};
|
||||
std::memcpy(&cmd, commandBytes, sizeof(cmd));
|
||||
if (cmd.count == 0 || cmd.instanceCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetCurrentBaseInstance(cmd.baseInstance);
|
||||
g_GLESFuncs.glDrawArraysInstanced(
|
||||
mode, static_cast<GLint>(cmd.first), static_cast<GLsizei>(cmd.count),
|
||||
static_cast<GLsizei>(cmd.instanceCount));
|
||||
SetCurrentBaseInstance(0);
|
||||
}
|
||||
|
||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
||||
|
||||
@@ -301,7 +301,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramBinary, GLuint program, GLenum binary
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramParameteri, GLuint program, GLenum pname, GLint value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramParameteri, program, pname, value)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateFramebuffer, GLenum target, GLsizei numAttachments, const GLenum* attachments) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateFramebuffer, target, numAttachments, attachments)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateSubFramebuffer, GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateSubFramebuffer, target, numAttachments, attachments, x, y, width, height)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TexStorage2D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexStorage2D, target, levels, internalformat, width, height)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, TexStorage2D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexStorage2D, target, levels, internalformat, width, height)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, TexStorage3D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexStorage3D, target, levels, internalformat, width, height, depth)
|
||||
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetInternalformativ, GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetInternalformativ, target, internalformat, pname, bufSize, params)
|
||||
DECLARE_GL_FUNCTION_HEAD(void, DispatchCompute, GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DispatchCompute, num_groups_x, num_groups_y, num_groups_z)
|
||||
|
||||
@@ -1870,6 +1870,20 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
}
|
||||
|
||||
void TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
|
||||
const auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
|
||||
const auto textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
|
||||
if (!TextureImpl::ValidateTextureTarget(textureTarget)) return;
|
||||
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return;
|
||||
|
||||
auto& activeUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
|
||||
auto& bindingSlot = activeUnit.GetBindingSlot(textureTarget);
|
||||
auto& textureObject = bindingSlot.GetBoundObject();
|
||||
if (!TextureImpl::ValidateTextureObject(textureObject)) return;
|
||||
|
||||
TextureStorage2D(textureObject->GetExternalIndex(), levels, internalformat, width, height);
|
||||
}
|
||||
|
||||
void TextureSubImage2D(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type, const void* pixels) {
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void* pixels);
|
||||
void GetTextureParameteriv(GLuint texture, GLenum pname, GLint* params);
|
||||
void GetTextureLevelParameteriv(GLuint texture, GLint level, GLenum pname, GLint* params);
|
||||
void TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
|
||||
void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width,
|
||||
GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels);
|
||||
void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
|
||||
|
||||
@@ -99,6 +99,30 @@ TEST_F(TextureTest, BoundTexSubImage2DUsesCompactRowsAfterUnpackProcessing) {
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(TextureTest, BoundTexStorage2DAllocatesRedTextureForSubImageUpdates) {
|
||||
GLuint texture = 0;
|
||||
MG_Impl::GLImpl::GenTextures(1, &texture);
|
||||
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
MG_Impl::GLImpl::TexStorage2D(GL_TEXTURE_2D, 1, GL_R8, 32, 32);
|
||||
|
||||
const auto textureObject = MG_State::pGLContext->GetTextureObject(texture);
|
||||
auto* mipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
|
||||
ASSERT_NE(mipmapObject, nullptr);
|
||||
EXPECT_EQ(mipmapObject->GetMipmapTexelSize(TextureUploadTarget::Texture2D, 0), IntVec3(32, 32, 1));
|
||||
EXPECT_TRUE(textureObject->IsComplete());
|
||||
|
||||
const Uint8 pixels[4 * 4] = {
|
||||
1, 2, 3, 4,
|
||||
5, 6, 7, 8,
|
||||
9, 10, 11, 12,
|
||||
13, 14, 15, 16,
|
||||
};
|
||||
MG_Impl::GLImpl::TexSubImage2D(GL_TEXTURE_2D, 0, 20, 28, 4, 4, GL_RED, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||
}
|
||||
|
||||
TEST_F(TextureTest, GetTextureImageReadsNamedObjectWithoutBinding) {
|
||||
GLuint texture = 0;
|
||||
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
|
||||
|
||||
Reference in New Issue
Block a user