diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index 0505432b..2b1cc32f 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -602,12 +602,12 @@ namespace MobileGL::MG_Backend::DirectGLES { const SizeT bytesPerPixel = MG_Util::GetInputBytesPerPixel(mglInternalFormat, texturePixelDataType); const SizeT totalBytes = width * height * bytesPerPixel; - MG_State::GLState::MipmapLevelInput mipmap = - MG_State::GLState::MipmapLevelInput({width, height, 1}, level, false, 0, - {nullptr, totalBytes}); + // MG_State::GLState::MipmapLevelInput mipmap = + // MG_State::GLState::MipmapLevelInput({width, height, 1}, level, false, 0, + // {nullptr, totalBytes}); textureObject->SetInternalFormat(mglInternalFormat); - textureObject->SetMipmapLevel(mipmap); + textureObject->AllocateStorage(TextureUploadTarget::Texture2D, level, {{width, height, 1}, totalBytes}); } void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.cpp b/MobileGL/MG_Backend/DirectGLES/Managers.cpp index 417fc425..0f62bb2d 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Managers.cpp @@ -273,10 +273,12 @@ namespace MobileGL::MG_Backend::DirectGLES { MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); }); + const auto mipmapCount = stateTextureObject->GetMipmapLevelCount(); + const auto baseSize = stateTextureObject->GetBaseSize(); StateTextureBasicInfo currentTextureInfo = { - stateTextureObject->GetFormat(), static_cast(stateTextureObject->GetBaseSize().x()), - static_cast(stateTextureObject->GetBaseSize().y()), - static_cast(stateTextureObject->GetBaseSize().z()), stateTextureObject->GetMipmaps().size()}; + stateTextureObject->GetFormat(), static_cast(baseSize.x()), + static_cast(baseSize.y()), + static_cast(baseSize.z()), mipmapCount }; Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo); @@ -285,34 +287,34 @@ namespace MobileGL::MG_Backend::DirectGLES { m_backendTextureId); // Regenerate all mipmap levels - const auto& mipmaps = stateTextureObject->GetMipmaps(); GLenum glInternalFormat, glType, glFormat; TextureImpl::GenerateTextureFormatInfo(stateTextureObject->GetFormat(), &glInternalFormat, &glType, &glFormat); - for (SizeT level = 0; level < mipmaps.size(); ++level) { - const auto& mipmap = mipmaps[level]; - + for (SizeT level = 0; level < mipmapCount; ++level) { + // TODO: deal with multiple upload target texture + auto levelTexelSize = stateTextureObject->GetMipmapTexelSize(TextureUploadTarget::Texture2D, level); + auto levelByteSize = stateTextureObject->GetMipmapByteSize(TextureUploadTarget::Texture2D, level); BufferImpl::BackendBufferBindingProtector pixelUnpackProtector = BufferImpl::BackendBufferBindingProtector(GL_PIXEL_UNPACK_BUFFER); errorLopper.Clear(); MG_External::GLES::glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); MG_External::GLES::glTexImage2D(GL_TEXTURE_2D, static_cast(level), glInternalFormat, - static_cast(mipmap.size.x()), - static_cast(mipmap.size.y()), 0, glFormat, glType, - mipmap.hasData ? mipmap.data.data() : nullptr); + static_cast(levelTexelSize.x()), + static_cast(levelTexelSize.y()), 0, glFormat, glType, + (levelByteSize != 0) ? stateTextureObject->MapMipmapData(TextureUploadTarget::Texture2D, level) : nullptr); - errorLopper.Loop([index = stateTextureObject->GetExternalIndex(), &mipmap, level, glInternalFormat, glFormat, glType, file = __FILE__, line = __LINE__, func = __func__](GLenum err) { - MGLOG_D("%s(%s:%d) ES error: %s, texobj %d, mip %d (%dx%d, %s, %s, %s)", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str(), - index, level, mipmap.size.x(), mipmap.size.y(), - MG_Util::ConvertGLEnumToString(glInternalFormat).c_str(), - MG_Util::ConvertGLEnumToString(glFormat).c_str(), - MG_Util::ConvertGLEnumToString(glType).c_str() - ); - }); + // errorLopper.Loop([index = stateTextureObject->GetExternalIndex(), &mipmap, level, glInternalFormat, glFormat, glType, file = __FILE__, line = __LINE__, func = __func__](GLenum err) { + // MGLOG_D("%s(%s:%d) ES error: %s, texobj %d, mip %d (%dx%d, %s, %s, %s)", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str(), + // index, level, mipmap.size.x(), mipmap.size.y(), + // MG_Util::ConvertGLEnumToString(glInternalFormat).c_str(), + // MG_Util::ConvertGLEnumToString(glFormat).c_str(), + // MG_Util::ConvertGLEnumToString(glType).c_str() + // ); + // }); // TODO: handle more texture types MGLOG_D("Regenerated mipmap level %d for texture with ID: %u", level, m_backendTextureId); - stateTextureObject->UnmarkMipmapDirty(level); + stateTextureObject->MarkStorageDirty(TextureUploadTarget::Texture2D, level, false); } m_isInitialized = true; @@ -418,17 +420,18 @@ namespace MobileGL::MG_Backend::DirectGLES { } { // Update all dirty mipmap levels - const auto& mipmaps = stateTextureObject->GetMipmaps(); + const auto mipmapCount = stateTextureObject->GetMipmapLevelCount(); GLenum glInternalFormat, glType, glFormat; TextureImpl::GenerateTextureFormatInfo(stateTextureObject->GetFormat(), &glInternalFormat, &glType, &glFormat); - for (const auto& mipmap : stateTextureObject->GetMipmaps()) { - if (!mipmap.dirty) { + for (SizeT level = 0; level < mipmapCount; ++level) { + if (!stateTextureObject->IsStorageDirty(TextureUploadTarget::Texture2D, level)) { continue; } - if (mipmap.data.empty()) { - MGLOG_W("Mipmap level %d has no data, skipping update.", mipmap.level); + auto byteSize = stateTextureObject->GetMipmapByteSize(TextureUploadTarget::Texture2D, level); + if (byteSize == 0) { + MGLOG_W("Mipmap level %d has no data, skipping update.", level); continue; } @@ -438,15 +441,16 @@ namespace MobileGL::MG_Backend::DirectGLES { errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { MGLOG_D("%s(%s:%d) ES error: %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str()); }); - MG_External::GLES::glTexSubImage2D(GL_TEXTURE_2D, static_cast(mipmap.level), 0, 0, - static_cast(mipmap.size.x()), - static_cast(mipmap.size.y()), glFormat, glType, - mipmap.hasData ? mipmap.data.data() : nullptr); - errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__, &mipmap, glFormat, glType](GLenum err) { - MGLOG_D("%s(%s:%d) ES error at glTexSubImage2D: %s (mip %d, %dx%d, %s, %s)", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str(), - mipmap.level, mipmap.size.x(), mipmap.size.y(), MG_Util::ConvertGLEnumToString(glFormat).c_str(), MG_Util::ConvertGLEnumToString(glType).c_str()); - }); - stateTextureObject->UnmarkMipmapDirty(mipmap.level); + auto texelSize = stateTextureObject->GetMipmapTexelSize(TextureUploadTarget::Texture2D, level); + MG_External::GLES::glTexSubImage2D(GL_TEXTURE_2D, static_cast(level), 0, 0, + static_cast(texelSize.x()), + static_cast(texelSize.y()), glFormat, glType, + (byteSize != 0) ? stateTextureObject->MapMipmapData(TextureUploadTarget::Texture2D, level) : nullptr); + // errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__, &mipmap, glFormat, glType](GLenum err) { + // MGLOG_D("%s(%s:%d) ES error at glTexSubImage2D: %s (mip %d, %dx%d, %s, %s)", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str(), + // mipmap.level, mipmap.size.x(), mipmap.size.y(), MG_Util::ConvertGLEnumToString(glFormat).c_str(), MG_Util::ConvertGLEnumToString(glType).c_str()); + // }); + stateTextureObject->MarkStorageDirty(TextureUploadTarget::Texture2D, level, false); } } errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) { diff --git a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp index 5abe36fd..a6d19e2f 100644 --- a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp +++ b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp @@ -64,8 +64,9 @@ namespace MobileGL { if (!TextureImpl::ValidateTextureSubImageOffsets(textureObject, xoffset, width, yoffset, height)) return; // ======================= Processing ================================ - auto& mipmap = textureObject->GetMipmap(level); - Vector& data = mipmap.data; + // auto& mipmap = textureObject->GetMipmap(level); + // Vector& data = mipmap.data; + auto texelSize = textureObject->GetMipmapTexelSize(textureUploadingTarget, level); SizeT imageSize = 0; const SizeT bytesPerPixel = MG_Util::GetInputBytesPerPixel(textureInternalFormat, texturePixelDataType); @@ -94,23 +95,24 @@ namespace MobileGL { } const SizeT srcRowSize = width * bytesPerPixel; - const SizeT destRowSize = mipmap.size.x() * bytesPerPixel; + const SizeT destRowSize = texelSize.x() * bytesPerPixel; - if (xoffset + width > static_cast(mipmap.size.x()) || - yoffset + height > static_cast(mipmap.size.y())) { + if (xoffset + width > static_cast(texelSize.x()) || + yoffset + height > static_cast(texelSize.y())) { MGLOG_E("TexSubImage2D_State: Specified region exceeds texture dimensions, xoffset: %d, yoffset: %d, " "width: %d, height: %d, mipmap size: (%d, %d)", - xoffset, yoffset, width, height, mipmap.size.x(), mipmap.size.y()); + xoffset, yoffset, width, height, texelSize.x(), texelSize.y()); free(processedPixels); return; } const auto* srcData = static_cast(processedPixels); - Uint8* destData = data.data(); - if (data.empty()) { - SizeT totalSize = mipmap.size.x() * mipmap.size.y() * bytesPerPixel; - data.resize(totalSize); - } + Uint8* destData = (Uint8*)textureObject->MapMipmapData(textureUploadingTarget, level); + // No allocation should be done here + // if (data.empty()) { + // SizeT totalSize = texelSize.x() * texelSize.y() * bytesPerPixel; + // data.resize(totalSize); + // } for (GLsizei y = 0; y < height; y++) { const SizeT destRowOffset = (yoffset + y) * destRowSize + xoffset * bytesPerPixel; @@ -120,8 +122,9 @@ namespace MobileGL { free(processedPixels); - mipmap.dirty = true; - mipmap.hasData = true; + textureObject->MarkStorageDirty(textureUploadingTarget, level, true); + // mipmap.dirty = true; + // mipmap.hasData = true; } void TexSubImage1D_State(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, @@ -375,10 +378,17 @@ namespace MobileGL { // ======================= Processing ================================ SizeT imageSize = 0; - void* processedPixels = nullptr; const SizeT bytesPerPixel = MG_Util::GetInputBytesPerPixel(textureInternalFormat, texturePixelDataType); const SizeT totalBytes = width * height * bytesPerPixel; + textureObject->SetInternalFormat(textureInternalFormat); + // Allocate in TextureObject + textureObject->AllocateStorage(textureUploadingTarget, level, {{width, height, 1}, isProxy ? 0 : totalBytes}); + + // if isProxy, no more pixel transfer needed below + if (isProxy) + return; + const void* originalPixels = pixels; // PBO @@ -391,25 +401,17 @@ namespace MobileGL { reinterpret_cast(pixels); } + void* processedPixels = nullptr; if (originalPixels) { processedPixels = MG_Util::PixelStoreProcessor::ProcessTexturePixelsDataUnpack( originalPixels, MG_State::pGLContext->GetPixelStoreParameters(true), bytesPerPixel, {width, height, 1}, false, imageSize); } else { - MGLOG_D("TexImage2D_State: No input pixel, do allocate only"); + MGLOG_D("TexImage2D_State: No input pixel and no PBO bound, no pixel transfer"); + return; } - MG_State::GLState::MipmapLevelInput mipmap = - MG_State::GLState::MipmapLevelInput({width, height, 1}, level, false, 0, - {(isProxy || originalPixels == nullptr) ? nullptr : malloc(totalBytes), isProxy ? 0 : totalBytes}); - - if (!isProxy && originalPixels != nullptr && !mipmap.inputData.data) { - MGLOG_E("TexImage2D_State: Failed to allocate memory for mipmap level data, size: %zu", totalBytes); - free(processedPixels); - processedPixels = nullptr; - } - - if (processedPixels && imageSize > 0 && !isProxy) { + if (processedPixels && imageSize > 0) { if (imageSize != totalBytes) { MGLOG_W("TexImage2D_State: Processed pixel data size (%zu) does not match expected size (%zu). " "This may indicate an alignment or processing issue.", @@ -417,20 +419,53 @@ namespace MobileGL { } const SizeT copySize = std::min(imageSize, totalBytes); - Memcpy(mipmap.inputData.data, processedPixels, copySize); - free(processedPixels); - } else if (processedPixels && !isProxy) { + DataPtr texelInput { processedPixels, copySize }; + textureObject->UpdateMipmapSubData(textureUploadingTarget, level, texelInput); + } else if (originalPixels) { MGLOG_E("TexImage2D_State: Failed to process pixel data, initializing with original data."); - Memcpy(mipmap.inputData.data, originalPixels, totalBytes); - } else { - if (mipmap.inputData.data) { - free(mipmap.inputData.data); - mipmap.inputData.data = nullptr; - } + DataPtr texelInput { (void*)originalPixels, totalBytes }; + textureObject->UpdateMipmapSubData(textureUploadingTarget, level, texelInput); } - textureObject->SetInternalFormat(textureInternalFormat); - textureObject->SetMipmapLevel(mipmap); - free(mipmap.inputData.data); + free(processedPixels); + + // MG_State::GLState::MipmapLevelInput mipmap = + // MG_State::GLState::MipmapLevelInput({width, height, 1}, level, false, 0, + // {(isProxy || originalPixels == nullptr) ? nullptr : malloc(totalBytes), isProxy ? 0 : totalBytes}); + + + // if (!isProxy && originalPixels != nullptr && !mipmap.inputData.data) { + // MGLOG_E("TexImage2D_State: Failed to allocate memory for mipmap level data, size: %zu", totalBytes); + // free(processedPixels); + // processedPixels = nullptr; + // } + + // if (!isProxy && originalPixels != nullptr) { + // MGLOG_E("TexImage2D_State: Failed to allocate memory for mipmap level data, size: %zu", totalBytes); + // free(processedPixels); + // processedPixels = nullptr; + // } + // + // if (processedPixels && imageSize > 0 && !isProxy) { + // if (imageSize != totalBytes) { + // MGLOG_W("TexImage2D_State: Processed pixel data size (%zu) does not match expected size (%zu). " + // "This may indicate an alignment or processing issue.", + // imageSize, totalBytes); + // } + // + // const SizeT copySize = std::min(imageSize, totalBytes); + // Memcpy(mipmap.inputData.data, processedPixels, copySize); + // free(processedPixels); + // } else if (processedPixels && !isProxy) { + // MGLOG_E("TexImage2D_State: Failed to process pixel data, initializing with original data."); + // Memcpy(mipmap.inputData.data, originalPixels, totalBytes); + // } else { + // if (mipmap.inputData.data) { + // free(mipmap.inputData.data); + // mipmap.inputData.data = nullptr; + // } + // } + // textureObject->SetMipmapLevel(mipmap); + // free(mipmap.inputData.data); } void TexImage1D_State(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, @@ -649,17 +684,17 @@ namespace MobileGL { switch (pname) { case GL_TEXTURE_WIDTH: if (params) { - *params = textureObject->GetMipmap(level).size.x(); + *params = textureObject->GetMipmapTexelSize(textureUploadingTarget, level).x(); } break; case GL_TEXTURE_HEIGHT: if (params) { - *params = textureObject->GetMipmap(level).size.y(); + *params = textureObject->GetMipmapTexelSize(textureUploadingTarget, level).y(); } break; case GL_TEXTURE_DEPTH: if (params) { - *params = textureObject->GetMipmap(level).size.z(); + *params = textureObject->GetMipmapTexelSize(textureUploadingTarget, level).z(); } break; case GL_TEXTURE_INTERNAL_FORMAT: @@ -715,17 +750,17 @@ namespace MobileGL { switch (pname) { case GL_TEXTURE_WIDTH: if (params) { - *params = textureObject->GetMipmap(level).size.x(); + *params = textureObject->GetMipmapTexelSize(textureUploadingTarget, level).x(); } break; case GL_TEXTURE_HEIGHT: if (params) { - *params = textureObject->GetMipmap(level).size.y(); + *params = textureObject->GetMipmapTexelSize(textureUploadingTarget, level).y(); } break; case GL_TEXTURE_DEPTH: if (params) { - *params = textureObject->GetMipmap(level).size.z(); + *params = textureObject->GetMipmapTexelSize(textureUploadingTarget, level).z(); } break; case GL_TEXTURE_INTERNAL_FORMAT: diff --git a/MobileGL/MG_Impl/Init.cpp b/MobileGL/MG_Impl/Init.cpp index 88caf025..b3c27256 100644 --- a/MobileGL/MG_Impl/Init.cpp +++ b/MobileGL/MG_Impl/Init.cpp @@ -16,13 +16,16 @@ namespace MobileGL { auto fbo0 = MG_State::pGLContext->CreateFramebufferObject(0); auto colorTex = MakeShared(0); colorTex->SetInternalFormat(TextureInternalFormat::RGBA8); - colorTex->SetMipmapLevel({{512, 512, 1}, 0, false, 0, {nullptr, 0}}); + colorTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, { {512, 512, 1}, 0 }); + // colorTex->SetMipmapLevel({{512, 512, 1}, 0, false, 0, {nullptr, 0}}); auto depthTex = MakeShared(0); depthTex->SetInternalFormat(TextureInternalFormat::Depth32FStencil8); - depthTex->SetMipmapLevel({{512, 512, 1}, 0, false, 0, {nullptr, 0}}); + depthTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, { {512, 512, 1}, 0 }); + // depthTex->SetMipmapLevel({{512, 512, 1}, 0, false, 0, {nullptr, 0}}); auto stencilTex = MakeShared(0); stencilTex->SetInternalFormat(TextureInternalFormat::Depth32FStencil8); - stencilTex->SetMipmapLevel({{512, 512, 1}, 0, false, 0, {nullptr, 0}}); + stencilTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, { {512, 512, 1}, 0 }); + // stencilTex->SetMipmapLevel({{512, 512, 1}, 0, false, 0, {nullptr, 0}}); fbo0->AttachTexture(FramebufferAttachmentType::Color0, colorTex); fbo0->AttachTexture(FramebufferAttachmentType::Depth, depthTex); fbo0->AttachTexture(FramebufferAttachmentType::Depth, depthTex); diff --git a/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.cpp b/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.cpp index ec95512b..b5c91dcf 100644 --- a/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.cpp +++ b/MobileGL/MG_State/GLState/FramebufferState/FramebufferObject.cpp @@ -51,7 +51,8 @@ namespace MobileGL { IntVec3 FramebufferAttachment::GetSize() const { if (IsTexture()) { - return m_texture->GetMipmap(m_textureLevel).size; + // TODO: get correct upload target + return m_texture->GetMipmapTexelSize(TextureUploadTarget::Texture2D, m_textureLevel); } else if (IsRenderbuffer()) { // TODO } diff --git a/MobileGL/MG_State/GLState/TextureState/TextureEnum.h b/MobileGL/MG_State/GLState/TextureState/TextureEnum.h new file mode 100644 index 00000000..81059eb2 --- /dev/null +++ b/MobileGL/MG_State/GLState/TextureState/TextureEnum.h @@ -0,0 +1,181 @@ +#pragma once + +namespace MobileGL { + enum class TextureTarget { + Texture1D, + Texture2D, + Texture3D, + TextureCubeMap, + TextureRectangle, + Texture2DMultisample, + TextureBuffer, + Texture1DArray, + Texture2DArray, + TextureCubeMapArray, + Texture2DMultisampleArray, + TextureTargetCount, + Unknown = -1 + }; + + // Don't tinker with order in this enum + // it is used in TextureStorage + enum class TextureUploadTarget { + Texture2D, + ProxyTexture2D, + Texture1DArray, + ProxyTexture1DArray, + TextureRectangle, + ProxyTextureRectangle, + CubeMapPositiveX, + CubeMapNegativeX, + CubeMapPositiveY, + CubeMapNegativeY, + CubeMapPositiveZ, + CubeMapNegativeZ, + ProxyCubeMap, + Texture2DMultisample, + ProxyTexture2DMultisample, + TextureUploadTargetCount, + Unknown = -1 + }; + + enum class TextureInputFormat { + Red, + RG, + RGB, + BGR, + RGBA, + BGRA, + RInteger, + RGInteger, + RGBInteger, + BGRInteger, + RGBAInteger, + BGRAInteger, + StencilIndex, + DepthComponent, + DepthStencil, + + FormatCount, + Unknown = -1 + }; + + enum class TextureInternalFormat { + R8, + R8Snorm, + R16, + R16Snorm, + RG8, + RG8Snorm, + RG16, + RG16Snorm, + R3G3B2, + RGB4, + RGB5, + RGB8, + RGB8Snorm, + RGB10, + RGB12, + RGB16Snorm, + RGBA2, + RGBA4, + RGB5A1, + RGBA8, + RGBA8Snorm, + RGB10A2, + RGB10A2UI, + RGBA12, + RGBA16, + SRGB8, + SRGB8Alpha8, + R16F, + RG16F, + RGB16F, + RGBA16F, + R32F, + RG32F, + RGB32F, + RGBA32F, + R11FG11FB10F, + RGB9E5, + R8I, + R8UI, + R16I, + R16UI, + R32I, + R32UI, + RG8I, + RG8UI, + RG16I, + RG16UI, + RG32I, + RG32UI, + RGB8I, + RGB8UI, + RGB16I, + RGB16UI, + RGB32I, + RGB32UI, + RGBA8I, + RGBA8UI, + RGBA16I, + RGBA16UI, + RGBA32I, + RGBA32UI, + DepthComponent16, + DepthComponent24, + DepthComponent32, // not a standard format in OpenGL core profile + DepthComponent32F, + Depth24Stencil8, + Depth32FStencil8, + + DepthComponent, + DepthStencil, + Red, + RG, + RGB, + RGBA, + + TextureInternalFormatCount, + Unknown = -1 + }; + + enum class TexturePixelDataType { + UnsignedByte, + Byte, + UnsignedShort, + Short, + UnsignedInt, + Int, + Float, + UnsignedByte332, + UnsignedByte233Rev, + UnsignedShort565, + UnsignedShort565Rev, + UnsignedShort4444, + UnsignedShort4444Rev, + UnsignedShort5551, + UnsignedShort1555Rev, + UnsignedInt8888, + UnsignedInt8888Rev, + UnsignedInt1010102, + UnsignedInt2101010Rev, + UnsignedInt101111Rev, // not a standard type in OpenGL core profile + UnsignedInt5999Rev, // not a standard type in OpenGL core profile + + TypeCount, + Unknown = -1 + }; + + enum class TextureSwizzleParam { + Red, + Green, + Blue, + Alpha, + Zero, + One, + + SwizzleParamCount, + Unknown = -1 + }; +} \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp b/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp index 27379880..780c3bd4 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp @@ -10,10 +10,45 @@ namespace MobileGL { m_sampler = MakeShared(0); } - void TextureObjectBase::SetMipmapLevel(const MipmapLevelInput& level) { - SetMipmapImpl(level); + Uint TextureObjectBase::GetMipmapLevelCount() const { + return m_textureStorage.GetLevelCount(); } + const IntVec3 TextureObjectBase::GetMipmapTexelSize(TextureUploadTarget target, Uint mipmapLevel) const { + return m_textureStorage.GetTexelSize(0, mipmapLevel); + } + + const SizeT TextureObjectBase::GetMipmapByteSize(TextureUploadTarget target, Uint mipmapLevel) const { + return m_textureStorage.GetByteSize(0, mipmapLevel); + } + + void TextureObjectBase::AllocateStorage(TextureUploadTarget uploadTarget, Uint mipmapLevel, + MipmapInput input) { + // don't care target, index always 0 + m_textureStorage.AllocateLevel(0, mipmapLevel, input); + } + void TextureObjectBase::UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel, + DataPtr input) { + // ditto + m_textureStorage.UpdateSubData(0, mipmapLevel, input); + } + void* TextureObjectBase::MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) { + return m_textureStorage.MapData(0, mipmapLevel); + } + + void TextureObjectBase::MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) { + // ditto + m_textureStorage.MarkDirty(0, mipmapLevel, dirty); + } + + bool TextureObjectBase::IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const { + return m_textureStorage.IsDirty(0, mipmapLevel); + } + + // void TextureObjectBase::SetMipmapLevel(const MipmapLevelInput& level) { + // SetMipmapImpl(level); + // } + TextureInternalFormat TextureObjectBase::GetFormat() const { return m_internalFormat; } @@ -23,32 +58,33 @@ namespace MobileGL { } IntVec3 TextureObjectBase::GetBaseSize() const { - if (m_mipmaps.empty()) { + if (m_textureStorage.GetLevelCount() == 0) { return {0, 0, 0}; } - return m_mipmaps[0].size; + return m_textureStorage.GetTexelSize(0, 0); } SharedPtr TextureObjectBase::GetSamplerObject() const { return m_sampler; } - const Vector& TextureObjectBase::GetMipmaps() const { - return m_mipmaps; - } + // const Vector& TextureObjectBase::GetMipmaps() const { + // return m_mipmaps; + // } Bool TextureObjectBase::IsComplete() const { if (m_internalFormat == TextureInternalFormat::Unknown) { return false; } - if (m_mipmaps.empty()) { + SizeT levelCount = m_textureStorage.GetLevelCount(); + if (levelCount == 0) { return false; } - for (size_t i = 0; i < m_mipmaps.size(); ++i) { - const auto& level = m_mipmaps[i]; - if (level.size.x() <= 0 || level.size.y() <= 0 || level.size.z() <= 0) { + for (size_t i = 0; i < levelCount; ++i) { + const auto& levelSize = m_textureStorage.GetTexelSize(0, i); + if (levelSize.x() <= 0 || levelSize.y() <= 0 || levelSize.z() <= 0) { return false; } } @@ -57,23 +93,23 @@ namespace MobileGL { return true; } - MipmapLevelInternal& TextureObjectBase::GetMipmap(Int index) { - if (index >= m_mipmaps.size()) { - MOBILEGL_ASSERT(false, "GetMipmap: index %d out of bounds, returning last mipmap level", index); - index = static_cast(m_mipmaps.size() - 1); - } - return m_mipmaps[index]; - } + // MipmapLevelInternal& TextureObjectBase::GetMipmap(TextureUploadTarget target, Int index) { + // if (index >= m_mipmaps.size()) { + // MOBILEGL_ASSERT(false, "GetMipmap: index %d out of bounds, returning last mipmap level", index); + // index = static_cast(m_mipmaps.size() - 1); + // } + // return m_mipmaps[index]; + // } void TextureObjectBase::SetInternalFormat(TextureInternalFormat format) { m_internalFormat = format; } - void TextureObjectBase::UnmarkMipmapDirty(Int index) { - if (index >= 0 && index < static_cast(m_mipmaps.size())) { - m_mipmaps[index].dirty = false; - } - } + // void TextureObjectBase::UnmarkMipmapDirty(Int index) { + // if (index >= 0 && index < static_cast(m_mipmaps.size())) { + // m_mipmaps[index].dirty = false; + // } + // } Uint TextureObjectBase::GetExternalIndex() const { return m_externalIndex; diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject.h b/MobileGL/MG_State/GLState/TextureState/TextureObject.h index ca87b1d1..a90dffc3 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject.h +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject.h @@ -1,186 +1,12 @@ #pragma once +#include "TextureEnum.h" +#include "TextureStorage.h" #include "MG_Util/Types.h" #include "../SamplerState/SamplerObject.h" #include #include namespace MobileGL { - enum class TextureTarget { - Texture1D, - Texture2D, - Texture3D, - TextureCubeMap, - TextureRectangle, - Texture2DMultisample, - TextureBuffer, - Texture1DArray, - Texture2DArray, - TextureCubeMapArray, - Texture2DMultisampleArray, - TextureTargetCount, - Unknown = -1 - }; - - enum class TextureUploadTarget { - Texture2D, - ProxyTexture2D, - Texture1DArray, - ProxyTexture1DArray, - TextureRectangle, - ProxyTextureRectangle, - CubeMapPositiveX, - CubeMapNegativeX, - CubeMapPositiveY, - CubeMapNegativeY, - CubeMapPositiveZ, - CubeMapNegativeZ, - ProxyCubeMap, - Texture2DMultisample, - ProxyTexture2DMultisample, - TextureUploadTargetCount, - Unknown = -1 - }; - - enum class TextureInputFormat { - Red, - RG, - RGB, - BGR, - RGBA, - BGRA, - RInteger, - RGInteger, - RGBInteger, - BGRInteger, - RGBAInteger, - BGRAInteger, - StencilIndex, - DepthComponent, - DepthStencil, - - FormatCount, - Unknown = -1 - }; - - enum class TextureInternalFormat { - R8, - R8Snorm, - R16, - R16Snorm, - RG8, - RG8Snorm, - RG16, - RG16Snorm, - R3G3B2, - RGB4, - RGB5, - RGB8, - RGB8Snorm, - RGB10, - RGB12, - RGB16Snorm, - RGBA2, - RGBA4, - RGB5A1, - RGBA8, - RGBA8Snorm, - RGB10A2, - RGB10A2UI, - RGBA12, - RGBA16, - SRGB8, - SRGB8Alpha8, - R16F, - RG16F, - RGB16F, - RGBA16F, - R32F, - RG32F, - RGB32F, - RGBA32F, - R11FG11FB10F, - RGB9E5, - R8I, - R8UI, - R16I, - R16UI, - R32I, - R32UI, - RG8I, - RG8UI, - RG16I, - RG16UI, - RG32I, - RG32UI, - RGB8I, - RGB8UI, - RGB16I, - RGB16UI, - RGB32I, - RGB32UI, - RGBA8I, - RGBA8UI, - RGBA16I, - RGBA16UI, - RGBA32I, - RGBA32UI, - DepthComponent16, - DepthComponent24, - DepthComponent32, // not a standard format in OpenGL core profile - DepthComponent32F, - Depth24Stencil8, - Depth32FStencil8, - - DepthComponent, - DepthStencil, - Red, - RG, - RGB, - RGBA, - - TextureInternalFormatCount, - Unknown = -1 - }; - - enum class TexturePixelDataType { - UnsignedByte, - Byte, - UnsignedShort, - Short, - UnsignedInt, - Int, - Float, - UnsignedByte332, - UnsignedByte233Rev, - UnsignedShort565, - UnsignedShort565Rev, - UnsignedShort4444, - UnsignedShort4444Rev, - UnsignedShort5551, - UnsignedShort1555Rev, - UnsignedInt8888, - UnsignedInt8888Rev, - UnsignedInt1010102, - UnsignedInt2101010Rev, - UnsignedInt101111Rev, // not a standard type in OpenGL core profile - UnsignedInt5999Rev, // not a standard type in OpenGL core profile - - TypeCount, - Unknown = -1 - }; - - enum class TextureSwizzleParam { - Red, - Green, - Blue, - Alpha, - Zero, - One, - - SwizzleParamCount, - Unknown = -1 - }; - namespace MG_State { namespace GLState { struct MipmapLevelBase { @@ -217,10 +43,19 @@ namespace MobileGL { using TargetEnum = TextureTarget; virtual ~ITextureObject() = default; - virtual void SetMipmapLevel(const MipmapLevelInput& level) = 0; - virtual const Vector& GetMipmaps() const = 0; - virtual MipmapLevelInternal& GetMipmap(Int index) = 0; - virtual void UnmarkMipmapDirty(Int index) = 0; + // virtual void SetMipmapLevel(const MipmapLevelInput& level) = 0; + // virtual const Vector& GetMipmaps() const = 0; + // virtual MipmapLevelInternal& GetMipmap(Int index) = 0; + // virtual void UnmarkMipmapDirty(Int index) = 0; + + virtual Uint GetMipmapLevelCount() const = 0; + virtual const IntVec3 GetMipmapTexelSize(TextureUploadTarget target, Uint mipmapLevel) const = 0; + virtual const SizeT GetMipmapByteSize(TextureUploadTarget target, Uint mipmapLevel) const = 0; + virtual void AllocateStorage(TextureUploadTarget uploadTarget, Uint mipmapLevel, MipmapInput input) = 0; + virtual void UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel, DataPtr input) = 0; + virtual void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) = 0; + virtual void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) = 0; + virtual bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const = 0; virtual TextureInternalFormat GetFormat() const = 0; virtual TextureTarget GetTarget() const = 0; @@ -243,10 +78,19 @@ namespace MobileGL { TextureObjectBase(TextureTarget target, Uint externalIndex); virtual ~TextureObjectBase() = default; - void SetMipmapLevel(const MipmapLevelInput& level) override; - const Vector& GetMipmaps() const override; - MipmapLevelInternal& GetMipmap(Int index) override; - void UnmarkMipmapDirty(Int index) override; + // void SetMipmapLevel(const MipmapLevelInput& level) override; + // const Vector& GetMipmaps() const override; + // MipmapLevelInternal& GetMipmap(TextureUploadTarget target, Int index) override; + // void UnmarkMipmapDirty(Int index) override; + + Uint GetMipmapLevelCount() const override; + const IntVec3 GetMipmapTexelSize(TextureUploadTarget target, Uint mipmapLevel) const override; + const SizeT GetMipmapByteSize(TextureUploadTarget target, Uint mipmapLevel) const override; + void AllocateStorage(TextureUploadTarget uploadTarget, Uint mipmapLevel, MipmapInput input) override; + void UpdateMipmapSubData(TextureUploadTarget uploadTarget, Uint mipmapLevel, DataPtr input) override; + void* MapMipmapData(TextureUploadTarget uploadTarget, Uint mipmapLevel) override; + void MarkStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel, bool dirty) override; + bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const override; TextureInternalFormat GetFormat() const override; TextureTarget GetTarget() const override; @@ -264,12 +108,13 @@ namespace MobileGL { void SetMaxLevel(Uint maxLevel) override; protected: - virtual void SetMipmapImpl(const MipmapLevelInput& level) = 0; + // virtual void SetMipmapImpl(const MipmapLevelInput& level) = 0; const Uint m_externalIndex; const TextureTarget m_target = TextureTarget::Unknown; TextureInternalFormat m_internalFormat = TextureInternalFormat::Unknown; - Vector m_mipmaps = {}; + // Vector m_mipmaps = {}; + TextureStorage<1> m_textureStorage; SharedPtr m_sampler = nullptr; FloatVec4 m_borderColor = {0.0f, 0.0f, 0.0f, 0.0f}; TextureSwizzleParam m_swizzleParams[4] = {TextureSwizzleParam::Red, TextureSwizzleParam::Green, diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject1D.cpp b/MobileGL/MG_State/GLState/TextureState/TextureObject1D.cpp index 3db2afbc..4e342e7c 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject1D.cpp +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject1D.cpp @@ -6,11 +6,11 @@ namespace MobileGL { TextureObject1D::TextureObject1D(Uint externalIndex) : TextureObjectBase(TextureTarget::Texture1D, externalIndex) {} - void TextureObject1D::SetMipmapImpl(const MipmapLevelInput& level) { - if (level.size.x() > 0) { - m_mipmaps.push_back(MipmapLevelInternal(level)); - } - } + // void TextureObject1D::SetMipmapImpl(const MipmapLevelInput& level) { + // if (level.size.x() > 0) { + // m_mipmaps.push_back(MipmapLevelInternal(level)); + // } + // } } } } \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject1D.h b/MobileGL/MG_State/GLState/TextureState/TextureObject1D.h index aff5cfd5..a75a66dd 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject1D.h +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject1D.h @@ -9,7 +9,7 @@ namespace MobileGL { explicit TextureObject1D(Uint externalIndex); protected: - void SetMipmapImpl(const MipmapLevelInput& level) override; + // void SetMipmapImpl(const MipmapLevelInput& level) override; }; } } diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject2D.cpp b/MobileGL/MG_State/GLState/TextureState/TextureObject2D.cpp index 270a96b9..27751443 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject2D.cpp +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject2D.cpp @@ -6,11 +6,11 @@ namespace MobileGL { TextureObject2D::TextureObject2D(Uint externalIndex) : TextureObjectBase(TextureTarget::Texture2D, externalIndex) {} - void TextureObject2D::SetMipmapImpl(const MipmapLevelInput& level) { - if (level.size.x() > 0 && level.size.y() > 0) { - m_mipmaps.push_back(MipmapLevelInternal(level)); - } - } + // void TextureObject2D::SetMipmapImpl(const MipmapLevelInput& level) { + // if (level.size.x() > 0 && level.size.y() > 0) { + // m_mipmaps.push_back(MipmapLevelInternal(level)); + // } + // } } } } \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject2D.h b/MobileGL/MG_State/GLState/TextureState/TextureObject2D.h index f349f53b..3da3fe59 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject2D.h +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject2D.h @@ -9,7 +9,7 @@ namespace MobileGL { explicit TextureObject2D(Uint externalIndex); protected: - void SetMipmapImpl(const MipmapLevelInput& level) override; + // void SetMipmapImpl(const MipmapLevelInput& level) override; }; } } diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject3D.cpp b/MobileGL/MG_State/GLState/TextureState/TextureObject3D.cpp index 6fda7f3b..c3de75b2 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject3D.cpp +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject3D.cpp @@ -6,11 +6,11 @@ namespace MobileGL { TextureObject3D::TextureObject3D(Uint externalIndex) : TextureObjectBase(TextureTarget::Texture3D, externalIndex) {} - void TextureObject3D::SetMipmapImpl(const MipmapLevelInput& level) { - if (level.size.x() > 0 && level.size.y() > 0 && level.size.z() > 0) { - m_mipmaps.push_back(MipmapLevelInternal(level)); - } - } + // void TextureObject3D::SetMipmapImpl(const MipmapLevelInput& level) { + // if (level.size.x() > 0 && level.size.y() > 0 && level.size.z() > 0) { + // m_mipmaps.push_back(MipmapLevelInternal(level)); + // } + // } } } } \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject3D.h b/MobileGL/MG_State/GLState/TextureState/TextureObject3D.h index 45eeff20..0e1a592c 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObject3D.h +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject3D.h @@ -9,7 +9,7 @@ namespace MobileGL { explicit TextureObject3D(Uint externalIndex); protected: - void SetMipmapImpl(const MipmapLevelInput& level) override; + // void SetMipmapImpl(const MipmapLevelInput& level) override; }; } } diff --git a/MobileGL/MG_State/GLState/TextureState/TextureStorage.h b/MobileGL/MG_State/GLState/TextureState/TextureStorage.h new file mode 100644 index 00000000..62df6e48 --- /dev/null +++ b/MobileGL/MG_State/GLState/TextureState/TextureStorage.h @@ -0,0 +1,103 @@ +#pragma once +#include "TextureEnum.h" +#include "MG_Util/Types.h" +#include "MG_Util/Math/VectorTypes.h" + +namespace MobileGL { + namespace MG_State { + namespace GLState { + struct MipmapInput { + IntVec3 texelSize = {0, 0, 0}; + SizeT byteSize = 0; + }; + + template + class TextureStorage { + public: + TextureStorage() { + static_assert(TargetCount > 0, "Mipmap size must be greater than zero"); + } + + void AllocateLevel(Uint targetIndex, Uint level, MipmapInput input) { + MOBILEGL_ASSERT(targetIndex < TargetCount, "AllocateLevel: target invalid"); + + auto& targetData = m_data[targetIndex]; + targetData.reserve(std::bit_ceil(level + 1)); + targetData.resize(level + 1); + auto& targetTexelSizes = m_texelSizes[targetIndex]; + targetTexelSizes.reserve(std::bit_ceil(level + 1)); + targetTexelSizes.resize(level + 1); + targetTexelSizes[level] = input.texelSize; + auto& dirtyArr = m_isDirty[targetIndex]; + dirtyArr.resize(level + 1, true); + + auto& data = targetData[level]; + data.resize(input.byteSize, 0); + // if (input.texelData.data && input.texelData.size > 0) { + // const Uint8* src = static_cast(input.texelData.data); + // Memcpy(data.data(), src, input.texelData.size); + // } + } + + void UpdateSubData(Uint targetIndex, Uint level, DataPtr input) { + MOBILEGL_ASSERT(targetIndex < TargetCount, "UpdateSubData: target invalid"); + auto& targetData = m_data[targetIndex]; + MOBILEGL_ASSERT(level < targetData.size(), "UpdateSubData: level out of range"); + auto& levelData = targetData[level]; + MOBILEGL_ASSERT(levelData.size() < input.size, "UpdateSubData: input data larger than allocated"); + + if (input.data && input.size > 0) { + const Uint8* src = static_cast(input.data); + Memcpy(levelData.data(), src, input.size); + m_isDirty[targetIndex][level] = false; + } + } + + void* MapData(Uint targetIndex, Uint level) { + MOBILEGL_ASSERT(targetIndex < TargetCount, "UpdateSubData: target invalid"); + auto& targetData = m_data[targetIndex]; + MOBILEGL_ASSERT(level < targetData.size(), "UpdateSubData: level out of range"); + auto& levelData = targetData[level]; + return levelData.data(); + } + + IntVec3 GetTexelSize(Uint targetIndex, Uint level) const { + MOBILEGL_ASSERT(targetIndex < TargetCount, "GetTexelSize: target invalid"); + + auto& targetTexelSizes = m_texelSizes[targetIndex]; + if (level >= targetTexelSizes.size()) + return {0, 0, 0}; + return targetTexelSizes[level]; + } + + SizeT GetByteSize(Uint targetIndex, Uint level) const { + MOBILEGL_ASSERT(targetIndex < TargetCount, "GetByteSize: target invalid"); + + auto& data = m_data[targetIndex]; + return data[level].size(); + } + + SizeT GetLevelCount() const { + return m_data[0].size(); + } + + void MarkDirty(Uint targetIndex, Uint level, bool dirty) { + MOBILEGL_ASSERT(targetIndex < TargetCount, "MarkDirty: target invalid"); + MOBILEGL_ASSERT(level < m_isDirty[targetIndex].size(), "MarkDirty: level out of range"); + m_isDirty[targetIndex][level] = dirty; + } + + bool IsDirty(Uint targetIndex, Uint level) const { + MOBILEGL_ASSERT(targetIndex < TargetCount, "IsDirty: target invalid"); + MOBILEGL_ASSERT(level < m_isDirty[targetIndex].size(), "IsDirty: level out of range"); + return m_isDirty[targetIndex][level]; + } + + protected: + Array, TargetCount> m_texelSizes; + Array>, TargetCount> m_data; + Array, TargetCount> m_isDirty; + }; + } + } +}