mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
Compare commits
79
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67069d4a12 | ||
|
|
4a38e7224e | ||
|
|
645f2f748f | ||
|
|
5652f9ae5f | ||
|
|
f3b0b242dd | ||
|
|
876cb7bcd3 | ||
|
|
ee9a121c6f | ||
|
|
00439c5c4a | ||
|
|
d7286a5832 | ||
|
|
972804fdc7 | ||
|
|
bca7328421 | ||
|
|
8097c0d7b1 | ||
|
|
641f54e1b7 | ||
|
|
c36bfe0843 | ||
|
|
8ae66521e3 | ||
|
|
6e21fd9a35 | ||
|
|
a2e8faafe5 | ||
|
|
668fa3033e | ||
|
|
139f3f978d | ||
|
|
09f96e5ba5 | ||
|
|
592a69b1c4 | ||
|
|
9211341ae7 | ||
|
|
5f9d354adb | ||
|
|
0ae36b71f5 | ||
|
|
20e2768f27 | ||
|
|
00c8b5ae3a | ||
|
|
7687c19b33 | ||
|
|
fc3a7cd5f1 | ||
|
|
0b7f906533 | ||
|
|
c78a94ed09 | ||
|
|
debcb171ce | ||
|
|
282468c9d5 | ||
|
|
34b06da83b | ||
|
|
3d55f38dab | ||
|
|
16426db244 | ||
|
|
6f8c76f06c | ||
|
|
43f2043478 | ||
|
|
f61f068e28 | ||
|
|
e234d471fe | ||
|
|
6ff97a9bb1 | ||
|
|
8adf1d3b8a | ||
|
|
2935279603 | ||
|
|
918b39bb63 | ||
|
|
963e88943c | ||
|
|
1a75bcba5e | ||
|
|
b64309edfc | ||
|
|
e3f1db0a9a | ||
|
|
2c848ab44b | ||
|
|
9b23594415 | ||
|
|
e2e52965df | ||
|
|
6e7907f183 | ||
|
|
b4be1292b8 | ||
|
|
db58f4c214 | ||
|
|
59bad77176 | ||
|
|
3504fca8da | ||
|
|
e61817ff6a | ||
|
|
b9df28838c | ||
|
|
fff00e65c4 | ||
|
|
8320b4f456 | ||
|
|
a757669df5 | ||
|
|
e16c0645c0 | ||
|
|
8d37763fd3 | ||
|
|
e0d0551e7b | ||
|
|
caa814e8f9 | ||
|
|
2502d32a2e | ||
|
|
e57dd3529e | ||
|
|
4b8d809237 | ||
|
|
d42182befc | ||
|
|
5efdb1016e | ||
|
|
15e24cda78 | ||
|
|
5013108a7f | ||
|
|
359ba1c572 | ||
|
|
733523011b | ||
|
|
14fc13c34d | ||
|
|
e9fee1358d | ||
|
|
dae3dd9996 | ||
|
|
556db8b02e | ||
|
|
96e993eecf | ||
|
|
fb3e2123cc |
@@ -14,7 +14,6 @@ bugprone-forwarding-reference-overload,
|
||||
bugprone-inaccurate-erase,
|
||||
bugprone-incorrect-roundings,
|
||||
bugprone-integer-division,
|
||||
bugprone-lambda-function-name,
|
||||
bugprone-macro-parentheses,
|
||||
bugprone-macro-repeated-side-effects,
|
||||
bugprone-misplaced-operator-in-strlen-in-alloc,
|
||||
@@ -63,7 +62,6 @@ cert-str34-c,
|
||||
cppcoreguidelines-interfaces-global-init,
|
||||
cppcoreguidelines-narrowing-conversions,
|
||||
cppcoreguidelines-pro-type-member-init,
|
||||
cppcoreguidelines-pro-type-static-cast-downcast,
|
||||
cppcoreguidelines-slicing,
|
||||
google-default-arguments,
|
||||
google-runtime-operator,
|
||||
|
||||
@@ -19,3 +19,9 @@
|
||||
[submodule "3rdparty/VulkanMemoryAllocator"]
|
||||
path = 3rdparty/VulkanMemoryAllocator
|
||||
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
|
||||
[submodule "3rdparty/Vulkan-Utility-Libraries"]
|
||||
path = 3rdparty/Vulkan-Utility-Libraries
|
||||
url = https://github.com/KhronosGroup/Vulkan-Utility-Libraries.git
|
||||
[submodule "3rdparty/Vulkan-Headers"]
|
||||
path = 3rdparty/Vulkan-Headers
|
||||
url = https://github.com/KhronosGroup/Vulkan-Headers.git
|
||||
|
||||
+1
Submodule 3rdparty/Vulkan-Headers added at ad9ce1235e
+1
Submodule 3rdparty/Vulkan-Utility-Libraries added at 738ec97a3f
+8
-2
@@ -108,6 +108,8 @@ set(SPIRV_CROSS_STATIC ON CACHE BOOL "Prefer static libs" FORCE)
|
||||
add_subdirectory(3rdparty/glslang)
|
||||
add_subdirectory(3rdparty/SPIRV-Cross)
|
||||
add_subdirectory(3rdparty/VulkanMemoryAllocator)
|
||||
add_subdirectory(3rdparty/Vulkan-Headers)
|
||||
add_subdirectory(3rdparty/Vulkan-Utility-Libraries)
|
||||
|
||||
set(XXHASH_BUILD_XXHSUM OFF)
|
||||
option(BUILD_SHARED_LIBS OFF)
|
||||
@@ -160,6 +162,8 @@ set(SOURCE_FILES
|
||||
MobileGL/MG_Util/Converters/GLToMG/RenderStateEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/GLToMG/ProgramEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToMG/TextureEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToVk/RenderStateEnumConverter.cpp
|
||||
MobileGL/MG_Util/Converters/MGToVk/TextureEnumConverter.cpp
|
||||
|
||||
MobileGL/MG_Util/Classifiers/TextureEnumClassifier.cpp
|
||||
|
||||
@@ -223,9 +227,10 @@ set(SOURCE_FILES
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateBuilder.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkSamplerManager.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp
|
||||
MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureSamplerManager.cpp
|
||||
|
||||
MobileGL/MG_State/GLState/Core.cpp
|
||||
MobileGL/MG_State/EGLState/Core.cpp
|
||||
@@ -262,6 +267,7 @@ set(MOBILEGL_LINK_LIBRARIES
|
||||
SPIRV-Tools
|
||||
xxHash::xxhash
|
||||
GPUOpen::VulkanMemoryAllocator
|
||||
Vulkan::UtilityHeaders
|
||||
)
|
||||
|
||||
set(MOBILEGL_COMPILE_DEF
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ namespace MobileGL::MG_Config {
|
||||
inline const String ProjectName = "MobileGL";
|
||||
inline const String CoreName = "MobileGL Core";
|
||||
inline const String CoreVendor = "MobileGL-Dev (BZLZHH, Swung0x48, Tungsten)";
|
||||
inline const Version CoreVersion = {26, 2, 0, "-dev", VersionType::Development};
|
||||
inline const Version CoreVersion = {26, 3, 0, "-dev", VersionType::Development};
|
||||
inline const VersionStringFormatAttrib DefaultVersionStringFormatAttrib = {2, 2, 0, true, true};
|
||||
inline const Uint64 CacheVersion = 0;
|
||||
|
||||
|
||||
+4
-4
@@ -34,10 +34,10 @@ namespace MobileGL {
|
||||
void Destroy() {
|
||||
MGLOG_I("MobileGL closing...");
|
||||
glslang::FinalizeProcess();
|
||||
delete MG_State::pGLContext;
|
||||
delete MG_State::pEGLContext;
|
||||
delete MG_Impl::GLImpl::TextureImpl::pProxyTextureManager;
|
||||
delete MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
||||
MG_State::pGLContext.reset();
|
||||
MG_State::pEGLContext.reset();
|
||||
MG_Impl::GLImpl::TextureImpl::pProxyTextureManager.reset();
|
||||
MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo.reset();
|
||||
MG_Util::Debug::Close();
|
||||
|
||||
// TODO: add and use Destroy functions for other subsystems
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "DirectGLES.h"
|
||||
#include "EGL/egl.h"
|
||||
#include "MG_Util/Types.h"
|
||||
#include "Utils.h"
|
||||
#include "Managers.h"
|
||||
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
|
||||
@@ -45,7 +46,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
namespace DebugImpl {
|
||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
||||
void ErrorLopper::Loop(std::function<void(GLenum)> func) {
|
||||
void ErrorLopper::Loop(const std::function<void(GLenum)>& func) {
|
||||
GLenum err = g_GLESFuncs.glGetError();
|
||||
while (err != GL_NO_ERROR) {
|
||||
func(err);
|
||||
@@ -68,14 +69,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
Clear();
|
||||
}
|
||||
#else
|
||||
void ErrorLopper::Loop(std::function<void(GLenum)> func) {}
|
||||
void ErrorLopper::Loop(const std::function<void(GLenum)>& func) {}
|
||||
void ErrorLopper::Clear() {}
|
||||
ErrorLopper::ErrorLopper() {}
|
||||
ErrorLopper::~ErrorLopper() {}
|
||||
ErrorLopper::ErrorLopper() = default;
|
||||
ErrorLopper::~ErrorLopper() = default;
|
||||
#endif
|
||||
|
||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
|
||||
OpenGLScopeMarker::OpenGLScopeMarker(String scopeName) {
|
||||
OpenGLScopeMarker::OpenGLScopeMarker(const String& scopeName) {
|
||||
g_GLESFuncs.glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, scopeName.c_str());
|
||||
}
|
||||
|
||||
@@ -83,7 +84,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
g_GLESFuncs.glPopDebugGroup();
|
||||
}
|
||||
#else
|
||||
OpenGLScopeMarker::OpenGLScopeMarker(String scopeName) {}
|
||||
OpenGLScopeMarker::OpenGLScopeMarker(const String& scopeName) {}
|
||||
|
||||
OpenGLScopeMarker::~OpenGLScopeMarker() {}
|
||||
#endif
|
||||
@@ -92,31 +93,28 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// TODO: deletion for deleted objects
|
||||
|
||||
namespace BufferImpl {
|
||||
void CreateAndSyncBufferObject(SharedPtr<MG_State::GLState::BufferObject>& bufferObject) {
|
||||
void CreateAndSyncBufferObject(const SharedPtr<MG_State::GLState::BufferObject>& bufferObject) {
|
||||
if (!(bufferObject->GetChangeBits() & BufferChangeBits::DirtyBit)) return;
|
||||
|
||||
const auto& backendBufferIt = g_backendBufferObjects.find(bufferObject);
|
||||
SharedPtr<BackendBufferObject> backendBufferObject;
|
||||
if (backendBufferIt == g_backendBufferObjects.end()) {
|
||||
backendBufferObject = MakeShared<BackendBufferObject>();
|
||||
g_backendBufferObjects[bufferObject] = backendBufferObject;
|
||||
} else {
|
||||
backendBufferObject = backendBufferIt->second;
|
||||
const auto& backendBufferIt = g_backendBufferObjects.find(bufferObject.get());
|
||||
Bool exist = (backendBufferIt != g_backendBufferObjects.end());
|
||||
auto& backendObj = exist ? backendBufferIt->second : g_backendBufferObjects.GetOrCreate(bufferObject);
|
||||
if (!exist) {
|
||||
backendObj = MakeShared<BackendBufferObject>();
|
||||
}
|
||||
backendBufferObject->SyncToBackend(bufferObject);
|
||||
backendObj->SyncToBackend(bufferObject);
|
||||
}
|
||||
|
||||
void SyncNeccessaryBuffers(Bool includeIBO = false, Bool includeIndirectBuffer = false) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
g_backendBufferObjects.CollectGarbageIfNeeded();
|
||||
|
||||
// All buffers we need are:
|
||||
// 1.VBO 2.IBO (if needed) 3.UBO 4.IndirectBuffer (if needed) 5.SSBO (TODO)
|
||||
// PBO is not needed since it should be handled in frontend
|
||||
|
||||
// static Vector<SharedPtr<MG_State::GLState::BufferObject>> buffersToSync;
|
||||
// buffersToSync.clear();
|
||||
|
||||
const auto& currentVAOObject = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!currentVAOObject) {
|
||||
MGLOG_E("No VAO is currently bound, cannot sync necessary buffers.");
|
||||
@@ -126,7 +124,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// VBO
|
||||
for (const auto& attrib : currentVAOObject->GetAllAttributes()) {
|
||||
if (!attrib.Enabled) continue;
|
||||
auto bufferObject = attrib.Buffer;
|
||||
auto& bufferObject = attrib.Buffer;
|
||||
if (bufferObject) {
|
||||
CreateAndSyncBufferObject(bufferObject);
|
||||
}
|
||||
@@ -134,7 +132,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
// IBO
|
||||
if (includeIBO) {
|
||||
auto possibleIBO = currentVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
|
||||
auto& possibleIBO = currentVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
|
||||
if (possibleIBO) {
|
||||
CreateAndSyncBufferObject(possibleIBO);
|
||||
}
|
||||
@@ -142,7 +140,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
// Indirect Buffer Object
|
||||
if (includeIndirectBuffer) {
|
||||
auto possibleIndirectBuffer =
|
||||
auto& possibleIndirectBuffer =
|
||||
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
|
||||
if (possibleIndirectBuffer) {
|
||||
CreateAndSyncBufferObject(possibleIndirectBuffer);
|
||||
@@ -153,7 +151,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
auto uboBindingPointCnt = MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::Uniform);
|
||||
for (SizeT i = 0; i < uboBindingPointCnt; ++i) {
|
||||
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, i);
|
||||
auto obj = point.GetBoundObject();
|
||||
auto& obj = point.GetBoundObject();
|
||||
if (obj) {
|
||||
CreateAndSyncBufferObject(obj);
|
||||
}
|
||||
@@ -166,48 +164,49 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
auto currentVAOObject = MG_State::pGLContext->GetBoundVertexArray();
|
||||
g_backendVertexArrayObjects.CollectGarbageIfNeeded();
|
||||
|
||||
auto& currentVAOObject = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!currentVAOObject) {
|
||||
MGLOG_E("No VAO is currently bound, cannot sync current VAO.");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& backendVAOIt = g_backendVertexArrayObjects.find(currentVAOObject);
|
||||
SharedPtr<VertexArrayImpl::BackendVertexArrayObject> backendVAOObject;
|
||||
if (backendVAOIt == g_backendVertexArrayObjects.end()) {
|
||||
backendVAOObject = MakeShared<VertexArrayImpl::BackendVertexArrayObject>();
|
||||
g_backendVertexArrayObjects[currentVAOObject] = backendVAOObject;
|
||||
} else {
|
||||
backendVAOObject = backendVAOIt->second;
|
||||
const auto& backendVAOIt = g_backendVertexArrayObjects.find(currentVAOObject.get());
|
||||
Bool exist = (backendVAOIt != g_backendVertexArrayObjects.end());
|
||||
auto& backendObj = exist ? backendVAOIt->second : g_backendVertexArrayObjects.GetOrCreate(currentVAOObject);
|
||||
if (!exist) {
|
||||
backendObj = MakeShared<VertexArrayImpl::BackendVertexArrayObject>();
|
||||
}
|
||||
backendVAOObject->SyncToBackend(currentVAOObject);
|
||||
backendObj->SyncToBackend(currentVAOObject);
|
||||
}
|
||||
} // namespace VertexArrayImpl
|
||||
|
||||
namespace TextureImpl {
|
||||
SharedPtr<BackendTextureObject> SyncTextureObjectToBackend(
|
||||
SharedPtr<MG_State::GLState::ITextureObject>& textureObject) {
|
||||
SharedPtr<BackendTextureObject>& SyncTextureObjectToBackend(
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& textureObject) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
const auto& backendTextureIt = g_backendTextureObjects.find(textureObject);
|
||||
SharedPtr<BackendTextureObject> backendTextureObject;
|
||||
if (backendTextureIt == g_backendTextureObjects.end()) {
|
||||
backendTextureObject = MakeShared<BackendTextureObject>();
|
||||
g_backendTextureObjects[textureObject] = backendTextureObject;
|
||||
} else {
|
||||
backendTextureObject = backendTextureIt->second;
|
||||
const auto& backendTextureIt = g_backendTextureObjects.find(textureObject.get());
|
||||
Bool exist = (backendTextureIt != g_backendTextureObjects.end());
|
||||
auto& backendObj = exist ? backendTextureIt->second : g_backendTextureObjects.GetOrCreate(textureObject);
|
||||
if (!exist) {
|
||||
backendObj = MakeShared<BackendTextureObject>();
|
||||
}
|
||||
backendTextureObject->SyncTextureParamsToBackend(textureObject);
|
||||
backendTextureObject->SyncBuiltinSamplerToBackend(textureObject);
|
||||
backendTextureObject->SyncMipmapsToBackend(textureObject);
|
||||
return backendTextureObject;
|
||||
backendObj->SyncTextureParamsToBackend(textureObject);
|
||||
backendObj->SyncBuiltinSamplerToBackend(textureObject);
|
||||
backendObj->SyncMipmapsToBackend(textureObject);
|
||||
|
||||
return backendObj;
|
||||
}
|
||||
|
||||
void SyncNeccessaryTextures() {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
g_backendTextureObjects.CollectGarbageIfNeeded();
|
||||
|
||||
// All textures we need are:
|
||||
// 1. textures bound to texture units (TODO: only sync ones that are used in current program)
|
||||
// 2. textures used in current FBO
|
||||
@@ -216,7 +215,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
for (int index = 0; index < MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS; ++index) {
|
||||
auto& unit = MG_State::pGLContext->GetTextureUnitObject(index);
|
||||
for (const auto& bindingSlot : unit.GetAllBindingSlots()) {
|
||||
auto textureObject = bindingSlot.GetBoundObject();
|
||||
auto& textureObject = bindingSlot.GetBoundObject();
|
||||
if (textureObject) {
|
||||
SyncTextureObjectToBackend(textureObject);
|
||||
}
|
||||
@@ -228,7 +227,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
if (currentFBO) {
|
||||
for (const auto& attachment : currentFBO->GetAllAttachmentObjects()) {
|
||||
if (!attachment.IsTexture()) continue;
|
||||
auto textureObject = attachment.GetTexture();
|
||||
auto& textureObject = attachment.GetTexture();
|
||||
if (textureObject) {
|
||||
SyncTextureObjectToBackend(textureObject);
|
||||
}
|
||||
@@ -242,16 +241,20 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
g_backendFramebufferObjects.CollectGarbageIfNeeded();
|
||||
TextureImpl::g_backendTextureObjects.CollectGarbageIfNeeded();
|
||||
RenderbufferImpl::g_backendRenderbufferObjects.CollectGarbageIfNeeded();
|
||||
|
||||
const FramebufferTarget fboTargets[] = {FramebufferTarget::Draw, FramebufferTarget::Read};
|
||||
|
||||
MG_State::GLState::FramebufferObject* lastUpdatedFBO = nullptr;
|
||||
|
||||
for (auto target : fboTargets) {
|
||||
auto slot = MG_State::pGLContext->GetFramebufferBindingSlot(target);
|
||||
for (auto& target : fboTargets) {
|
||||
auto& slot = MG_State::pGLContext->GetFramebufferBindingSlot(target);
|
||||
auto version = slot.GetVersion();
|
||||
if (version == g_fboBindVersions[SizeT(target)]) continue;
|
||||
|
||||
auto currentFBO = slot.GetBoundObject();
|
||||
auto& currentFBO = slot.GetBoundObject();
|
||||
|
||||
if (!currentFBO) {
|
||||
MGLOG_E("No FBO is currently bound, cannot sync current FBO.");
|
||||
@@ -263,21 +266,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& backendFBOIt = g_backendFramebufferObjects.find(currentFBO);
|
||||
SharedPtr<BackendFramebufferObject> backendFBOObject;
|
||||
if (backendFBOIt == g_backendFramebufferObjects.end()) {
|
||||
backendFBOObject = MakeShared<BackendFramebufferObject>();
|
||||
g_backendFramebufferObjects[currentFBO] = backendFBOObject;
|
||||
} else {
|
||||
backendFBOObject = backendFBOIt->second;
|
||||
}
|
||||
|
||||
if (currentFBO.get() == lastUpdatedFBO) {
|
||||
MGLOG_D("Draw FBO and read FBO are the same, skipping sync.");
|
||||
} else {
|
||||
backendFBOObject->SyncToBackend(currentFBO, target);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& backendFBOIt = g_backendFramebufferObjects.find(currentFBO.get());
|
||||
Bool exist = (backendFBOIt != g_backendFramebufferObjects.end());
|
||||
auto& backendObj = exist ? backendFBOIt->second : g_backendFramebufferObjects.GetOrCreate(currentFBO);
|
||||
if (!exist) {
|
||||
backendObj = MakeShared<BackendFramebufferObject>();
|
||||
}
|
||||
backendObj->SyncToBackend(currentFBO, target);
|
||||
|
||||
lastUpdatedFBO = currentFBO.get();
|
||||
}
|
||||
}
|
||||
@@ -466,21 +467,23 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||
g_backendProgramObjects.CollectGarbageIfNeeded();
|
||||
SamplerImpl::g_backendSamplerObjects.CollectGarbageIfNeeded();
|
||||
|
||||
auto& currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||
if (!currentProgram || !currentProgram->GetLinkStatus()) {
|
||||
g_GLESFuncs.glUseProgram(0);
|
||||
return;
|
||||
}
|
||||
const auto& backendProgramIt = g_backendProgramObjects.find(currentProgram);
|
||||
SharedPtr<BackendProgramObjectImpl> backendProgram;
|
||||
if (backendProgramIt == g_backendProgramObjects.end()) {
|
||||
backendProgram = MakeShared<BackendProgramObjectImpl>();
|
||||
g_backendProgramObjects[currentProgram] = backendProgram;
|
||||
backendProgram->SyncToBackend(currentProgram);
|
||||
const auto& backendProgramIt = g_backendProgramObjects.find(currentProgram.get());
|
||||
Bool exist = (backendProgramIt != g_backendProgramObjects.end());
|
||||
auto& backendObj = exist ? backendProgramIt->second : g_backendProgramObjects.GetOrCreate(currentProgram);
|
||||
if (!exist) {
|
||||
backendObj = MakeShared<BackendProgramObjectImpl>();
|
||||
backendObj->SyncToBackend(currentProgram);
|
||||
} else {
|
||||
backendProgram = backendProgramIt->second;
|
||||
if (!backendProgram->GetBackendProgramId()) {
|
||||
backendProgram->SyncToBackend(currentProgram);
|
||||
if (!backendObj->GetBackendProgramId()) {
|
||||
backendObj->SyncToBackend(currentProgram);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -495,7 +498,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
const auto& currentFBO = slot.GetBoundObject();
|
||||
if (currentFBO && currentFBO != MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO) {
|
||||
const auto& backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find(currentFBO);
|
||||
const auto& backendFBOIt = FramebufferImpl::g_backendFramebufferObjects.find(currentFBO.get());
|
||||
if (backendFBOIt != FramebufferImpl::g_backendFramebufferObjects.end()) {
|
||||
backendFBOIt->second->Bind(target);
|
||||
} else {
|
||||
@@ -528,7 +531,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#endif
|
||||
const auto& currentVAO = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (currentVAO) {
|
||||
const auto& backendVAOIt = VertexArrayImpl::g_backendVertexArrayObjects.find(currentVAO);
|
||||
const auto& backendVAOIt = VertexArrayImpl::g_backendVertexArrayObjects.find(currentVAO.get());
|
||||
if (backendVAOIt != VertexArrayImpl::g_backendVertexArrayObjects.end()) {
|
||||
backendVAOIt->second->Bind();
|
||||
}
|
||||
@@ -556,7 +559,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
MG_Util::ConvertTextureTargetToString(target).c_str());
|
||||
continue;
|
||||
}
|
||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
|
||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
|
||||
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) continue;
|
||||
|
||||
GLenum targetGL = MG_Util::ConvertTextureTargetToGLEnum(target);
|
||||
@@ -566,7 +569,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// Bind sampler object if necessary
|
||||
const auto& samplerObject = textureUnit.GetSamplerObject();
|
||||
if (samplerObject) {
|
||||
const auto& backendSamplerIt = SamplerImpl::g_backendSamplerObjects.find(samplerObject);
|
||||
const auto& backendSamplerIt = SamplerImpl::g_backendSamplerObjects.find(samplerObject.get());
|
||||
if (backendSamplerIt != SamplerImpl::g_backendSamplerObjects.end()) {
|
||||
backendSamplerIt->second->Bind(unit);
|
||||
}
|
||||
@@ -581,7 +584,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedNC("BindCurrentProgram", TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
const auto& backendProgramIt = PrgramImpl::g_backendProgramObjects.find(currentProgram);
|
||||
const auto& backendProgramIt = PrgramImpl::g_backendProgramObjects.find(currentProgram.get());
|
||||
if (backendProgramIt != PrgramImpl::g_backendProgramObjects.end()) {
|
||||
backendProgramIt->second->Use();
|
||||
auto backendProgramId = backendProgramIt->second->GetBackendProgramId();
|
||||
@@ -623,11 +626,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
// Connect buffer to backend binding point
|
||||
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, binding);
|
||||
auto bufferObj = point.GetBoundObject();
|
||||
auto& bufferObj = point.GetBoundObject();
|
||||
auto range = point.GetRange();
|
||||
|
||||
if (bufferObj) {
|
||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObj);
|
||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObj.get());
|
||||
if (backendBufferIt != BufferImpl::g_backendBufferObjects.end()) {
|
||||
const auto& backendBufferObject = backendBufferIt->second;
|
||||
backendBufferObject->Bind(GL_UNIFORM_BUFFER);
|
||||
@@ -635,9 +638,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
g_GLESFuncs.glBindBufferBase(GL_UNIFORM_BUFFER, lastUBOBinding,
|
||||
backendBufferObject->GetBackendBufferId());
|
||||
} else {
|
||||
g_GLESFuncs.glBindBufferRange(GL_UNIFORM_BUFFER, lastUBOBinding,
|
||||
backendBufferObject->GetBackendBufferId(),
|
||||
range.start, range.end - range.start);
|
||||
g_GLESFuncs.glBindBufferRange(
|
||||
GL_UNIFORM_BUFFER, lastUBOBinding, backendBufferObject->GetBackendBufferId(),
|
||||
(GLintptr)range.start, (GLintptr)(range.end - range.start));
|
||||
}
|
||||
} else {
|
||||
MGLOG_E("No backend buffer found for UBO binding, cannot bind UBO.");
|
||||
@@ -660,18 +663,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
backendProgramIt->second->GetBackendProgramId(), name.c_str());
|
||||
g_GLESFuncs.glUniform1i(locAtBackend, unit);
|
||||
|
||||
auto samplerObject = MG_State::pGLContext->GetTextureUnitObject(unit).GetSamplerObject();
|
||||
auto& samplerObject = MG_State::pGLContext->GetTextureUnitObject(unit).GetSamplerObject();
|
||||
|
||||
if (samplerObject) {
|
||||
const auto& backendSamplerIt = SamplerImpl::g_backendSamplerObjects.find(samplerObject);
|
||||
SharedPtr<SamplerImpl::BackendSamplerObject> backendSamplerObject;
|
||||
if (backendSamplerIt == SamplerImpl::g_backendSamplerObjects.end()) {
|
||||
backendSamplerObject = MakeShared<SamplerImpl::BackendSamplerObject>();
|
||||
SamplerImpl::g_backendSamplerObjects[samplerObject] = backendSamplerObject;
|
||||
} else {
|
||||
backendSamplerObject = backendSamplerIt->second;
|
||||
const auto& backendSamplerIt =
|
||||
SamplerImpl::g_backendSamplerObjects.find(samplerObject.get());
|
||||
Bool exist = (backendSamplerIt != SamplerImpl::g_backendSamplerObjects.end());
|
||||
auto& backendObj = exist ? backendSamplerIt->second
|
||||
: SamplerImpl::g_backendSamplerObjects.GetOrCreate(samplerObject);
|
||||
if (!exist) {
|
||||
backendObj = MakeShared<SamplerImpl::BackendSamplerObject>();
|
||||
}
|
||||
backendSamplerObject->SyncToBackend(samplerObject);
|
||||
backendObj->SyncToBackend(samplerObject);
|
||||
} else {
|
||||
SamplerImpl::UnbindSampler(unit);
|
||||
}
|
||||
@@ -845,30 +848,29 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER
|
||||
DebugImpl::OpenGLScopeMarker marker(__func__);
|
||||
#endif
|
||||
DebugImpl::ErrorLopper errorLopper;
|
||||
|
||||
TextureImpl::SyncNeccessaryTextures();
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
FramebufferImpl::SyncCurrentFBO();
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
RenderStateImpl::SyncRenderState();
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
|
||||
BindCurrentFBO(FramebufferTarget::Draw);
|
||||
BindCurrentFBO(FramebufferTarget::Read);
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
MGLOG_D("ES %s(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)", __func__, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0,
|
||||
dstX1, dstY1, mask, MG_Util::ConvertGLEnumToString(filter).c_str());
|
||||
g_GLESFuncs.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
}
|
||||
@@ -895,15 +897,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
MG_Util::ConvertTextureTargetToString(textureTarget).c_str());
|
||||
}
|
||||
|
||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
|
||||
SharedPtr<TextureImpl::BackendTextureObject> backendTextureObject;
|
||||
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
|
||||
backendTextureObject = MakeShared<TextureImpl::BackendTextureObject>();
|
||||
TextureImpl::g_backendTextureObjects[textureObject] = backendTextureObject;
|
||||
} else {
|
||||
backendTextureObject = backendTextureIt->second;
|
||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
|
||||
Bool exist = (backendTextureIt != TextureImpl::g_backendTextureObjects.end());
|
||||
auto& backendObj =
|
||||
exist ? backendTextureIt->second : TextureImpl::g_backendTextureObjects.GetOrCreate(textureObject);
|
||||
if (!exist) {
|
||||
backendObj = MakeShared<TextureImpl::BackendTextureObject>();
|
||||
}
|
||||
backendTextureObject->Bind(target, unit);
|
||||
backendObj->Bind(target, unit);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -953,15 +954,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
DebugImpl::ErrorLopper errorLopper;
|
||||
MGLOG_D("%s: Backend", __func__);
|
||||
TextureImpl::SyncNeccessaryTextures();
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
FramebufferImpl::SyncCurrentFBO();
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
RenderStateImpl::SyncRenderState();
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
if (!UpdateTextureBindingAtTarget(target)) return;
|
||||
@@ -969,10 +970,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// Bind necessary FBO and texture
|
||||
BindCurrentFBO(FramebufferTarget::Read);
|
||||
Uint activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit();
|
||||
const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject(activeTextureUnit)
|
||||
const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject((Int)activeTextureUnit)
|
||||
.GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target))
|
||||
.GetBoundObject();
|
||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
|
||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
|
||||
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
|
||||
MGLOG_E("CopyTexSubImage2D: No backend texture found for texture %u.",
|
||||
textureObject ? textureObject->GetExternalIndex() : 0);
|
||||
@@ -998,19 +999,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
if (!isDepthFormat) {
|
||||
g_GLESFuncs.glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
} else {
|
||||
MGLOG_D("%s: Backend depth", __func__);
|
||||
g_GLESFuncs.glTexImage2D(target, level, (GLint)internalformat, width, height, border, format, type,
|
||||
nullptr);
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
|
||||
GLint currentTex = backendTextureIt->second->GetBackendTextureId();
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
auto currentTex = (GLint)backendTextureIt->second->GetBackendTextureId();
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
|
||||
@@ -1026,7 +1027,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
g_GLESFuncs.glBlitFramebuffer(x, y, x + width, y + height, 0, 0, width, height,
|
||||
GL_DEPTH_BUFFER_BIT | (isStencilFormat ? GL_STENCIL_BUFFER_BIT : 0),
|
||||
GL_NEAREST);
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
}
|
||||
@@ -1041,15 +1042,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
MGLOG_D("%s: Backend", __func__);
|
||||
TextureImpl::SyncNeccessaryTextures();
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
FramebufferImpl::SyncCurrentFBO();
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
RenderStateImpl::SyncRenderState();
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
|
||||
@@ -1057,11 +1058,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
// Bind necessary FBO and texture
|
||||
BindCurrentFBO(FramebufferTarget::Read);
|
||||
Uint activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit();
|
||||
auto activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit();
|
||||
const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject(activeTextureUnit)
|
||||
.GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target))
|
||||
.GetBoundObject();
|
||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
|
||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
|
||||
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
|
||||
MGLOG_E("CopyTexSubImage2D: No backend texture found for texture %u.",
|
||||
textureObject ? textureObject->GetExternalIndex() : 0);
|
||||
@@ -1069,12 +1070,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
backendTextureIt->second->Bind(target, activeTextureUnit);
|
||||
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
GLenum internalFormat;
|
||||
g_GLESFuncs.glGetTexLevelParameteriv(target, level, GL_TEXTURE_INTERNAL_FORMAT, (GLint*)&internalFormat);
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
auto mgInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalFormat);
|
||||
@@ -1084,19 +1085,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
if (!isDepthFormat) {
|
||||
g_GLESFuncs.glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
} else {
|
||||
MGLOG_D("%s: Backend depth", __func__);
|
||||
GLint currentTex = backendTextureIt->second->GetBackendTextureId();
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
auto currentTex = backendTextureIt->second->GetBackendTextureId();
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
GLenum attachment = isStencilFormat ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT;
|
||||
TempFBOBinder tempFBOBinder(false);
|
||||
g_GLESFuncs.glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, target, currentTex, level);
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
if (g_GLESFuncs.glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
@@ -1107,7 +1108,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
g_GLESFuncs.glBlitFramebuffer(
|
||||
x, y, x + width, y + height, xoffset, yoffset, xoffset + width, yoffset + height,
|
||||
GL_DEPTH_BUFFER_BIT | (isStencilFormat ? GL_STENCIL_BUFFER_BIT : 0), GL_NEAREST);
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
}
|
||||
@@ -1120,8 +1121,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
auto unitIndex = MG_State::pGLContext->GetActiveTextureUnit();
|
||||
auto& unit = MG_State::pGLContext->GetTextureUnitObject(unitIndex);
|
||||
auto& slot = unit.GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target));
|
||||
auto texture = slot.GetBoundObject();
|
||||
auto backendTexture = TextureImpl::SyncTextureObjectToBackend(texture);
|
||||
auto& texture = slot.GetBoundObject();
|
||||
auto& backendTexture = TextureImpl::SyncTextureObjectToBackend(texture);
|
||||
|
||||
backendTexture->Bind(target, unitIndex);
|
||||
g_GLESFuncs.glGenerateMipmap(target);
|
||||
@@ -1184,7 +1185,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
PixelStoreParameters m_prevParams;
|
||||
|
||||
PixelStoreParameters QueryCurrentGLPixelStoreParams(Bool isUnpack) {
|
||||
static PixelStoreParameters QueryCurrentGLPixelStoreParams(Bool isUnpack) {
|
||||
PixelStoreParameters p;
|
||||
if (!isUnpack) {
|
||||
g_GLESFuncs.glGetIntegerv(GL_PACK_ALIGNMENT, (GLint*)&p.Alignment);
|
||||
@@ -1214,7 +1215,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return p;
|
||||
}
|
||||
|
||||
void Sync(Bool isUnpack, const PixelStoreParameters& params) {
|
||||
static void Sync(Bool isUnpack, const PixelStoreParameters& params) {
|
||||
if (!isUnpack) {
|
||||
g_GLESFuncs.glPixelStorei(GL_PACK_ALIGNMENT, params.Alignment);
|
||||
g_GLESFuncs.glPixelStorei(GL_PACK_ROW_LENGTH, params.RowLength);
|
||||
@@ -1271,7 +1272,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
|
||||
// Handle PBO
|
||||
auto pixelPackBufferObject =
|
||||
auto& pixelPackBufferObject =
|
||||
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
||||
Bool usePBO;
|
||||
GLuint prevPixelPackBuffer = 0;
|
||||
@@ -1279,7 +1280,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
BufferImpl::CreateAndSyncBufferObject(pixelPackBufferObject);
|
||||
MGLOG_D("ReadPixels: Using PBO %u", pixelPackBufferObject->GetExternalIndex());
|
||||
usePBO = true;
|
||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(pixelPackBufferObject);
|
||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(pixelPackBufferObject.get());
|
||||
|
||||
if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) {
|
||||
MGLOG_E("ReadPixels: No backend buffer found for PBO %u.",
|
||||
@@ -1299,8 +1300,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
if (usePBO) {
|
||||
// pull back to client memory if PBO is used
|
||||
MGLOG_D("ReadPixels: PBO used, mapping buffer to client memory");
|
||||
GLvoid* pboMappedPtr = g_GLESFuncs.glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0,
|
||||
pixelPackBufferObject->GetSize(), GL_MAP_READ_BIT);
|
||||
GLvoid* pboMappedPtr = g_GLESFuncs.glMapBufferRange(
|
||||
GL_PIXEL_PACK_BUFFER, 0, (GLsizeiptr)pixelPackBufferObject->GetSize(), GL_MAP_READ_BIT);
|
||||
if (pboMappedPtr) {
|
||||
MGLOG_D("ReadPixels: Copying data from PBO to client memory");
|
||||
SizeT size = pixelPackBufferObject->GetSize();
|
||||
@@ -1345,7 +1346,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
MGLOG_D("GetTexImage: SyncCurrentFBO()");
|
||||
FramebufferImpl::SyncCurrentFBO();
|
||||
|
||||
Uint activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit();
|
||||
auto activeTextureUnit = MG_State::pGLContext->GetActiveTextureUnit();
|
||||
MGLOG_D("GetTexImage: active texture unit = %u", activeTextureUnit);
|
||||
|
||||
const auto& textureObject = MG_State::pGLContext->GetTextureUnitObject(activeTextureUnit)
|
||||
@@ -1355,7 +1356,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
MGLOG_D("GetTexImage: bound texture object = %p (name=%u)", textureObject.get(),
|
||||
textureObject ? textureObject->GetExternalIndex() : 0);
|
||||
|
||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
|
||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
|
||||
|
||||
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
|
||||
MGLOG_E("GetTexImage: No backend texture found for texture %u.",
|
||||
@@ -1383,14 +1384,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return;
|
||||
}
|
||||
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
|
||||
MGLOG_D("GetTexImage: Applying TempPixelStoreParameterSync (PACK)");
|
||||
TempPixelStoreParameterSync tempPackParamsSync(false);
|
||||
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
|
||||
@@ -1404,7 +1405,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
|
||||
|
||||
auto levelRange = textureMipmapObject->GetLevelRange();
|
||||
auto& levelRange = textureMipmapObject->GetLevelRange();
|
||||
MGLOG_D("GetTexImage: mipmap level range = [%d, %d)", levelRange.x(), levelRange.y());
|
||||
|
||||
if (level < levelRange.x() || level >= levelRange.y()) {
|
||||
@@ -1421,7 +1422,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
MGLOG_D("GetTexImage: mip level %d size = %dx%d", level, size.x(), size.y());
|
||||
|
||||
// Handle PBO
|
||||
auto pixelPackBufferObject =
|
||||
auto& pixelPackBufferObject =
|
||||
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
||||
Bool usePBO;
|
||||
GLuint prevPixelPackBuffer = 0;
|
||||
@@ -1429,7 +1430,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
BufferImpl::CreateAndSyncBufferObject(pixelPackBufferObject);
|
||||
MGLOG_D("GetTexImage: Using PBO %u", pixelPackBufferObject->GetExternalIndex());
|
||||
usePBO = true;
|
||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(pixelPackBufferObject);
|
||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(pixelPackBufferObject.get());
|
||||
if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) {
|
||||
MGLOG_E("GetTexImage: No backend buffer found for PBO %u.",
|
||||
pixelPackBufferObject ? pixelPackBufferObject->GetExternalIndex() : 0);
|
||||
@@ -1443,7 +1444,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
MGLOG_D("GetTexImage: Not using PBO");
|
||||
}
|
||||
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
MGLOG_D("GetTexImage: glReadPixels(0, 0, %d, %d, %s, %s, %p)", size.x(), size.y(),
|
||||
@@ -1451,14 +1452,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
pixels);
|
||||
g_GLESFuncs.glReadPixels(0, 0, size.x(), size.y(), esFormat, esType, pixels);
|
||||
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
if (usePBO) {
|
||||
// pull back to client memory if PBO is used
|
||||
MGLOG_D("ReadPixels: PBO used, mapping buffer to client memory");
|
||||
GLvoid* pboMappedPtr = g_GLESFuncs.glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0,
|
||||
pixelPackBufferObject->GetSize(), GL_MAP_READ_BIT);
|
||||
GLvoid* pboMappedPtr = g_GLESFuncs.glMapBufferRange(
|
||||
GL_PIXEL_PACK_BUFFER, 0, (GLsizeiptr)pixelPackBufferObject->GetSize(), GL_MAP_READ_BIT);
|
||||
if (pboMappedPtr) {
|
||||
MGLOG_D("ReadPixels: Copying data from PBO to client memory");
|
||||
SizeT size = pixelPackBufferObject->GetSize();
|
||||
@@ -1479,7 +1480,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
}
|
||||
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
|
||||
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||
});
|
||||
MGLOG_D("GetTexImage: finished");
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
// End of Source File Header
|
||||
|
||||
#include "Managers.h"
|
||||
#include "MG_State/GLState/TextureState/TextureEnum.h"
|
||||
#include "MG_State/GLState/TextureState/TextureObject.h"
|
||||
#include "MG_State/GLState/TextureState/TextureState.h"
|
||||
#include "MG_Util/Converters/GLToMG/TextureEnumConverter.h"
|
||||
#include "Utils.h"
|
||||
#include "DirectGLES.h"
|
||||
|
||||
@@ -18,6 +14,7 @@
|
||||
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToGL/DataTypeConverter.h>
|
||||
#include <MG_Util/Converters/MGToGL/BufferEnumConverter.h>
|
||||
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToGL/ProgramEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
|
||||
@@ -44,7 +41,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
}
|
||||
|
||||
void BackendBufferObject::SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
|
||||
void BackendBufferObject::SyncToBackend(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
@@ -105,7 +102,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
|
||||
void BackendBufferObject::SyncToBackend_glBufferData(
|
||||
SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
|
||||
const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
@@ -117,11 +114,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
GLenum usage = MG_Util::ConvertBufferUsageToGLEnum(stateBufferObject->GetUsage());
|
||||
|
||||
Bind();
|
||||
g_GLESFuncs.glBufferData(TempBufferTarget, size, data, usage);
|
||||
g_GLESFuncs.glBufferData(TempBufferTarget, (GLsizeiptr)size, data, usage);
|
||||
}
|
||||
|
||||
void BackendBufferObject::SyncToBackend_glBufferSubData(
|
||||
SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
|
||||
const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
@@ -130,7 +127,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
const void* data = stateBufferObject->GetDataReadOnly()->data();
|
||||
// dirty range: [range.start, range.end)
|
||||
auto ranges = stateBufferObject->GetDirtyRanges();
|
||||
auto& ranges = stateBufferObject->GetDirtyRanges();
|
||||
if (ranges.empty()) {
|
||||
MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId);
|
||||
return;
|
||||
@@ -138,20 +135,21 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
for (const auto& range : ranges) {
|
||||
Bind();
|
||||
g_GLESFuncs.glBufferSubData(TempBufferTarget, range.start, range.end - range.start,
|
||||
g_GLESFuncs.glBufferSubData(TempBufferTarget, (GLintptr)range.start,
|
||||
(GLintptr)(range.end - range.start),
|
||||
reinterpret_cast<const char*>(data) + range.start);
|
||||
}
|
||||
}
|
||||
|
||||
void BackendBufferObject::SyncToBackend_glMapBufferRange(
|
||||
SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject, Bool invalidate, Bool unsynchronized) {
|
||||
const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject, Bool invalidate, Bool unsynchronized) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
|
||||
MGLOG_D("Syncing buffer map (glMapBuffer) for object with ID : %u", m_backendBufferId);
|
||||
MGLOG_D("Mapping buffer with ID: %u", m_backendBufferId);
|
||||
auto ranges = stateBufferObject->GetDirtyRanges();
|
||||
auto& ranges = stateBufferObject->GetDirtyRanges();
|
||||
if (ranges.empty()) {
|
||||
MGLOG_D("No dirty range to sync for buffer with ID: %u", m_backendBufferId);
|
||||
return;
|
||||
@@ -159,18 +157,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
SizeT minStart = ranges.GetOverallMinStart();
|
||||
SizeT maxEnd = ranges.GetOverallMaxEnd();
|
||||
Bind();
|
||||
void* mappedData = g_GLESFuncs.glMapBufferRange(TempBufferTarget, minStart, maxEnd - minStart,
|
||||
(invalidate ? GL_MAP_INVALIDATE_RANGE_BIT : 0) |
|
||||
(unsynchronized ? GL_MAP_UNSYNCHRONIZED_BIT : 0) |
|
||||
GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
|
||||
void* mappedData = g_GLESFuncs.glMapBufferRange(
|
||||
TempBufferTarget, (GLintptr)minStart, (GLintptr)(maxEnd - minStart),
|
||||
(invalidate ? GL_MAP_INVALIDATE_RANGE_BIT : 0) | (unsynchronized ? GL_MAP_UNSYNCHRONIZED_BIT : 0) |
|
||||
GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
|
||||
const void* data = stateBufferObject->GetDataReadOnly()->data();
|
||||
if (mappedData) {
|
||||
MGLOG_D("Mapped buffer data successfully for object with ID: %u", m_backendBufferId);
|
||||
Memcpy(mappedData, reinterpret_cast<const char*>(data) + minStart, maxEnd - minStart);
|
||||
// Explicitly flush the dirty ranges
|
||||
for (const auto& range : ranges) {
|
||||
g_GLESFuncs.glFlushMappedBufferRange(TempBufferTarget, range.start - minStart,
|
||||
range.end - range.start);
|
||||
g_GLESFuncs.glFlushMappedBufferRange(TempBufferTarget, (GLintptr)(range.start - minStart),
|
||||
(GLintptr)(range.end - range.start));
|
||||
}
|
||||
g_GLESFuncs.glUnmapBuffer(TempBufferTarget);
|
||||
} else {
|
||||
@@ -191,7 +189,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
g_GLESFuncs.glBindBuffer(target, m_backendBufferId);
|
||||
}
|
||||
|
||||
UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>> g_backendBufferObjects;
|
||||
StateBackendObjectRegistry<MG_State::GLState::BufferObject, BackendBufferObject> g_backendBufferObjects;
|
||||
BackendBufferObject* g_boundVertexBufferObject = nullptr;
|
||||
} // namespace BufferImpl
|
||||
|
||||
@@ -209,22 +207,21 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
}
|
||||
|
||||
void BackendVertexArrayObject::Bind() {
|
||||
void BackendVertexArrayObject::Bind() const {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
g_GLESFuncs.glBindVertexArray(m_backendVAOId);
|
||||
}
|
||||
|
||||
void BackendVertexArrayObject::BindAttributeBuffer(Uint index,
|
||||
const MG_State::GLState::VertexAttribute& attrib) {
|
||||
inline void BindAttributeBuffer(const MG_State::GLState::VertexAttribute& attrib) {
|
||||
const auto& bufferObject = attrib.Buffer;
|
||||
if (!bufferObject) {
|
||||
MGLOG_W("Attribute has no bound buffer, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObject);
|
||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(bufferObject.get());
|
||||
if (backendBufferIt == BufferImpl::g_backendBufferObjects.end()) {
|
||||
MGLOG_E("No backend buffer found for attribute's buffer, cannot bind attribute.");
|
||||
return;
|
||||
@@ -234,7 +231,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
backendBufferObject->Bind(GL_ARRAY_BUFFER);
|
||||
}
|
||||
|
||||
void BackendVertexArrayObject::SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject) {
|
||||
void BackendVertexArrayObject::SyncToBackend(
|
||||
const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
@@ -268,7 +266,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
m_syncedAttributeVersions[attribIndex].BufferVersion;
|
||||
if (!needsSyncFormat && !needsSyncBuffer) continue;
|
||||
|
||||
BindAttributeBuffer(attribIndex, attrib);
|
||||
BindAttributeBuffer(attrib);
|
||||
|
||||
if (!attrib.IsInteger) {
|
||||
g_GLESFuncs.glVertexAttribPointer(
|
||||
@@ -289,7 +287,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
if (currentIndexBufferVersion != m_syncedIndexBufferVersion) {
|
||||
const auto& indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject();
|
||||
if (indexBufferBinding) {
|
||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(indexBufferBinding);
|
||||
const auto& backendBufferIt = BufferImpl::g_backendBufferObjects.find(indexBufferBinding.get());
|
||||
if (backendBufferIt != BufferImpl::g_backendBufferObjects.end()) {
|
||||
const auto& backendBufferObject = backendBufferIt->second;
|
||||
backendBufferObject->Bind(GL_ELEMENT_ARRAY_BUFFER);
|
||||
@@ -303,7 +301,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
m_syncedAttributeVersions = allAttributeVersions;
|
||||
}
|
||||
|
||||
UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>>
|
||||
StateBackendObjectRegistry<MG_State::GLState::VertexArrayObject, BackendVertexArrayObject>
|
||||
g_backendVertexArrayObjects;
|
||||
} // namespace VertexArrayImpl
|
||||
|
||||
@@ -336,7 +334,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
g_boundTexturesCache[unit][targetN] = this;
|
||||
}
|
||||
|
||||
Uint BackendTextureObject::GetBackendTextureId() {
|
||||
Uint BackendTextureObject::GetBackendTextureId() const {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
@@ -344,7 +342,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
|
||||
void BackendTextureObject::SyncMipmapsToBackend(
|
||||
SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
|
||||
if (!stateTextureObject) {
|
||||
MGLOG_E("State texture object is null, cannot sync to backend.");
|
||||
return;
|
||||
@@ -353,7 +351,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
DebugImpl::ErrorLopper errorLopper;
|
||||
|
||||
MGLOG_D("Syncing texture mipmaps with backend ID %u to backend for state ID %u", m_backendTextureId,
|
||||
stateTextureObject->GetExternalIndex());
|
||||
@@ -381,7 +378,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
|
||||
Bind(target);
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||
DebugImpl::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());
|
||||
});
|
||||
const auto baseSize = stateTextureObject->GetBaseSize();
|
||||
@@ -414,7 +411,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
&glFormat, &glType);
|
||||
|
||||
const auto& uploadTargets = textureMipmapObject->GetUploadTargets();
|
||||
for (auto uploadTarget : uploadTargets) {
|
||||
for (auto& uploadTarget : uploadTargets) {
|
||||
for (SizeT level = 0; level < mipmapCount; ++level) {
|
||||
auto levelTexelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level);
|
||||
auto levelByteSize = textureMipmapObject->GetMipmapByteSize(uploadTarget, level);
|
||||
@@ -429,22 +426,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
levelTexelSize.x(), levelTexelSize.y(), levelTexelSize.z(), levelByteSize, pData,
|
||||
levelDirty ? "true" : "false");
|
||||
|
||||
errorLopper.Clear();
|
||||
DebugImpl::ErrorLopper::Clear();
|
||||
g_GLESFuncs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
auto textureTarget = stateTextureObject->GetTarget();
|
||||
// TODO: handle more texture types
|
||||
switch (textureTarget) {
|
||||
case TextureTarget::Texture2D:
|
||||
case TextureTarget::TextureCubeMap: {
|
||||
g_GLESFuncs.glTexImage2D(glUploadTarget, static_cast<GLint>(level), glInternalFormat,
|
||||
static_cast<GLsizei>(levelTexelSize.x()),
|
||||
static_cast<GLsizei>(levelTexelSize.y()), 0, glFormat, glType,
|
||||
pData);
|
||||
g_GLESFuncs.glTexImage2D(
|
||||
glUploadTarget, static_cast<GLint>(level), (GLint)glInternalFormat,
|
||||
static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
|
||||
0, glFormat, glType, pData);
|
||||
break;
|
||||
}
|
||||
case TextureTarget::Texture3D: {
|
||||
g_GLESFuncs.glTexImage3D(
|
||||
glUploadTarget, static_cast<GLint>(level), glInternalFormat,
|
||||
glUploadTarget, static_cast<GLint>(level), (GLint)glInternalFormat,
|
||||
static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
|
||||
static_cast<GLsizei>(levelTexelSize.z()), 0, glFormat, glType, pData);
|
||||
break;
|
||||
@@ -454,8 +451,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
MG_Util::ConvertTextureTargetToString(textureTarget).c_str());
|
||||
}
|
||||
}
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__, glUploadTarget,
|
||||
glInternalFormat, glFormat, glType, pData](GLenum err) {
|
||||
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__,
|
||||
glUploadTarget, glInternalFormat, glFormat, glType,
|
||||
pData](GLenum err) {
|
||||
MGLOG_D("%s(%s:%d) ES error: %s. glTexImage*: target=%s, internalformat=%s, format=%s, "
|
||||
"type=%s, pixels=%p",
|
||||
func, file, line, MG_Util::ConvertGLEnumToString(err).c_str(),
|
||||
@@ -478,7 +476,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
TextureImpl::GenerateTextureFormatInfo(textureMipmapObject->GetFormat(), &glInternalFormat,
|
||||
&glFormat, &glType);
|
||||
const auto& uploadTargets = textureMipmapObject->GetUploadTargets();
|
||||
for (auto uploadTarget : uploadTargets) {
|
||||
for (auto& uploadTarget : uploadTargets) {
|
||||
for (SizeT level = 0; level < mipmapCount; ++level) {
|
||||
if (!textureMipmapObject->IsStorageDirty(uploadTarget, level)) {
|
||||
continue;
|
||||
@@ -499,10 +497,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
auto glUploadTarget = MG_Util::ConvertTextureUploadTargetToGLEnum(uploadTarget);
|
||||
g_GLESFuncs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
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());
|
||||
});
|
||||
DebugImpl::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());
|
||||
});
|
||||
auto texelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level);
|
||||
g_GLESFuncs.glTexSubImage2D(glUploadTarget, static_cast<GLint>(level), 0, 0,
|
||||
static_cast<GLsizei>(texelSize.x()),
|
||||
@@ -518,7 +517,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
auto* textureBufferObject =
|
||||
static_cast<MG_State::GLState::TextureObjectBuffer*>(stateTextureObject.get());
|
||||
auto& slot = textureBufferObject->GetBufferBindingSlot();
|
||||
auto buffer = slot.GetBoundObject();
|
||||
auto& buffer = slot.GetBoundObject();
|
||||
auto bufferIndex = buffer->GetExternalIndex();
|
||||
currentTextureInfo.bufferExternalIndex = bufferIndex;
|
||||
|
||||
@@ -530,10 +529,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// Need to sync texture buffer if not synced yet
|
||||
auto& backendBuffers = BufferImpl::g_backendBufferObjects;
|
||||
SharedPtr<BufferImpl::BackendBufferObject> backendBufferObject;
|
||||
const auto& backendBufferIt = backendBuffers.find(buffer);
|
||||
const auto& backendBufferIt = backendBuffers.find(buffer.get());
|
||||
if (backendBufferIt == backendBuffers.end()) {
|
||||
backendBufferObject = MakeShared<BufferImpl::BackendBufferObject>();
|
||||
backendBuffers[buffer] = backendBufferObject;
|
||||
auto& backendBufferSlot = backendBuffers.GetOrCreate(buffer);
|
||||
if (!backendBufferSlot) {
|
||||
backendBufferSlot = MakeShared<BufferImpl::BackendBufferObject>();
|
||||
}
|
||||
backendBufferObject = backendBufferSlot;
|
||||
} else {
|
||||
backendBufferObject = backendBufferIt->second;
|
||||
}
|
||||
@@ -553,7 +555,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
THROW_UNIMPL_EXCEPTION;
|
||||
}
|
||||
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||
DebugImpl::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());
|
||||
});
|
||||
|
||||
@@ -561,11 +563,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
|
||||
void BackendTextureObject::SyncBuiltinSamplerToBackend(
|
||||
SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
DebugImpl::ErrorLopper errorLopper;
|
||||
|
||||
if (!stateTextureObject) {
|
||||
MGLOG_E("State texture object is null, cannot sync to backend.");
|
||||
return;
|
||||
@@ -594,7 +596,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
|
||||
Bind(target);
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||
DebugImpl::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());
|
||||
});
|
||||
|
||||
@@ -607,28 +609,29 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
g_GLESFuncs.glTexParameteri(target, glName, \
|
||||
MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)); \
|
||||
m_cacheSamplerParameters.internalName = samplerParams.internalName; \
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__, \
|
||||
t = MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)](GLenum err) { \
|
||||
MGLOG_D("%s(%s:%d) ES error %s, GL_TEXTURE_MIN_FILTER = %s", func, file, line, \
|
||||
MG_Util::ConvertGLEnumToString(err).c_str(), MG_Util::ConvertGLEnumToString(t).c_str()); \
|
||||
}); \
|
||||
DebugImpl::ErrorLopper::Loop( \
|
||||
[file = __FILE__, line = __LINE__, func = __func__, \
|
||||
t = MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)](GLenum err) { \
|
||||
MGLOG_D("%s(%s:%d) ES error %s, GL_TEXTURE_MIN_FILTER = %s", func, file, line, \
|
||||
MG_Util::ConvertGLEnumToString(err).c_str(), MG_Util::ConvertGLEnumToString(t).c_str()); \
|
||||
}); \
|
||||
}
|
||||
|
||||
if (m_cacheSamplerParameters.minFilter != samplerParams.minFilter ||
|
||||
m_cacheSamplerParameters.mipmapMode != samplerParams.mipmapMode) {
|
||||
g_GLESFuncs.glTexParameteri(
|
||||
target, GL_TEXTURE_MIN_FILTER,
|
||||
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.minFilter, samplerParams.mipmapMode));
|
||||
g_GLESFuncs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER,
|
||||
(GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.minFilter,
|
||||
samplerParams.mipmapMode));
|
||||
m_cacheSamplerParameters.minFilter = samplerParams.minFilter;
|
||||
m_cacheSamplerParameters.mipmapMode = samplerParams.mipmapMode;
|
||||
}
|
||||
if (m_cacheSamplerParameters.magFilter != samplerParams.magFilter) {
|
||||
g_GLESFuncs.glTexParameteri(
|
||||
target, GL_TEXTURE_MAG_FILTER,
|
||||
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.magFilter, SamplerMipmapMode::None));
|
||||
(GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.magFilter, SamplerMipmapMode::None));
|
||||
m_cacheSamplerParameters.magFilter = samplerParams.magFilter;
|
||||
}
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||
DebugImpl::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());
|
||||
});
|
||||
|
||||
@@ -645,18 +648,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
g_GLESFuncs.glTexParameterf(target, GL_TEXTURE_MAX_LOD, samplerParams.maxLod);
|
||||
m_cacheSamplerParameters.maxLod = samplerParams.maxLod;
|
||||
}
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||
DebugImpl::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());
|
||||
});
|
||||
#undef SYNC_TEX_SAMPLER_PARAM_IF_CHANGED
|
||||
}
|
||||
|
||||
void BackendTextureObject::SyncTextureParamsToBackend(
|
||||
SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
DebugImpl::ErrorLopper errorLopper;
|
||||
|
||||
if (!stateTextureObject) {
|
||||
MGLOG_E("State texture object is null, cannot sync to backend.");
|
||||
return;
|
||||
@@ -683,7 +686,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
|
||||
Bind(target);
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||
DebugImpl::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());
|
||||
});
|
||||
|
||||
@@ -696,14 +699,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
g_GLESFuncs.glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, static_cast<GLint>(levelRange.x()));
|
||||
m_cacheLodRange.x() = levelRange.x();
|
||||
}
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||
DebugImpl::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());
|
||||
});
|
||||
if (m_cacheLodRange.y() != levelRange.y()) {
|
||||
g_GLESFuncs.glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, static_cast<GLint>(levelRange.y()));
|
||||
m_cacheLodRange.y() = levelRange.y();
|
||||
}
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||
DebugImpl::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());
|
||||
});
|
||||
|
||||
@@ -720,7 +723,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
SYNC_TEX_SWIZZLE_PARAM_IF_CHANGED(a(), GL_TEXTURE_SWIZZLE_A);
|
||||
#undef SYNC_TEX_SWIZZLE_PARAM_IF_CHANGED
|
||||
m_cacheSwizzleParams = swizzleParams;
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||
DebugImpl::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());
|
||||
});
|
||||
}
|
||||
@@ -730,7 +733,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
GLfloat borderColorArray[4] = {borderColor.x(), borderColor.y(), borderColor.z(), borderColor.w()};
|
||||
g_GLESFuncs.glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, borderColorArray);
|
||||
m_cacheBorderColor = borderColor;
|
||||
errorLopper.Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||
DebugImpl::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());
|
||||
});
|
||||
}
|
||||
@@ -760,8 +763,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>,
|
||||
MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
|
||||
g_boundTexturesCache;
|
||||
UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>>
|
||||
g_backendTextureObjects;
|
||||
StateBackendObjectRegistry<MG_State::GLState::ITextureObject, BackendTextureObject> g_backendTextureObjects;
|
||||
} // namespace TextureImpl
|
||||
|
||||
namespace FramebufferImpl {
|
||||
@@ -778,7 +780,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
}
|
||||
|
||||
void BackendFramebufferObject::Bind(FramebufferTarget target) {
|
||||
void BackendFramebufferObject::Bind(FramebufferTarget target) const {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
@@ -788,12 +790,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId);
|
||||
}
|
||||
|
||||
Bool BackendFramebufferObject::SyncAttachmentObject(
|
||||
GLenum glFBOTarget, const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
|
||||
GLenum glBackendAttachment) {
|
||||
static Bool SyncAttachmentObject(GLenum glFBOTarget,
|
||||
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
|
||||
GLenum glBackendAttachment) {
|
||||
if (attachmentObject.IsTexture()) {
|
||||
const auto& textureObject = attachmentObject.GetTexture();
|
||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
|
||||
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
|
||||
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
|
||||
MGLOG_E("%s: No backend texture found for FBO attachment, cannot bind texture.", __func__);
|
||||
return false;
|
||||
@@ -807,11 +809,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
} else if (attachmentObject.IsRenderbuffer()) {
|
||||
const auto& renderbufferObject = attachmentObject.GetRenderbuffer();
|
||||
const auto& backendRenderbufferIt =
|
||||
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
|
||||
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject.get());
|
||||
SharedPtr<RenderbufferImpl::BackendRenderbufferObject> backendRenderbufferObject;
|
||||
if (backendRenderbufferIt == RenderbufferImpl::g_backendRenderbufferObjects.end()) {
|
||||
backendRenderbufferObject = MakeShared<RenderbufferImpl::BackendRenderbufferObject>();
|
||||
RenderbufferImpl::g_backendRenderbufferObjects[renderbufferObject] = backendRenderbufferObject;
|
||||
auto& backendRenderbufferSlot =
|
||||
RenderbufferImpl::g_backendRenderbufferObjects.GetOrCreate(renderbufferObject);
|
||||
if (!backendRenderbufferSlot) {
|
||||
backendRenderbufferSlot = MakeShared<RenderbufferImpl::BackendRenderbufferObject>();
|
||||
}
|
||||
backendRenderbufferObject = backendRenderbufferSlot;
|
||||
} else {
|
||||
backendRenderbufferObject = backendRenderbufferIt->second;
|
||||
}
|
||||
@@ -824,8 +830,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return true;
|
||||
}
|
||||
|
||||
void BackendFramebufferObject::SyncToBackend(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
|
||||
FramebufferTarget asTarget) {
|
||||
void BackendFramebufferObject::SyncToBackend(
|
||||
const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject, FramebufferTarget asTarget) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
@@ -853,7 +859,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
std::fill(m_backendDrawBuffers, m_backendDrawBuffers + FramebufferObject::MAX_DRAW_BUFFERS, GL_NONE);
|
||||
int nEffectiveBuffers = 0;
|
||||
for (GLint i = 0; i < FramebufferObject::MAX_DRAW_BUFFERS; ++i) {
|
||||
auto frontendBuf = stateDrawBuffers[i];
|
||||
auto& frontendBuf = stateDrawBuffers[i];
|
||||
if (frontendBuf == FramebufferAttachmentType::None) {
|
||||
m_backendDrawBuffers[i] = GL_NONE;
|
||||
continue;
|
||||
@@ -892,7 +898,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
const auto& attachmentVersions = stateFBOObject->GetAllFramebufferAttachmentVersions();
|
||||
for (SizeT i = 0; i < attachments.size(); ++i) {
|
||||
const auto& attachmentObject = attachments[i];
|
||||
FramebufferAttachmentType frontendType = static_cast<FramebufferAttachmentType>(i);
|
||||
auto frontendType = static_cast<FramebufferAttachmentType>(i);
|
||||
GLenum glBackendAttachment = GL_NONE;
|
||||
if (frontendType >= FramebufferAttachmentType::Color0 &&
|
||||
frontendType <= FramebufferAttachmentType::Color31)
|
||||
@@ -928,7 +934,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// Verify that the backend object's name and parameters match the frontend attachment state
|
||||
if (attachmentObject.IsTexture()) {
|
||||
const auto& textureObject = attachmentObject.GetTexture();
|
||||
auto backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject);
|
||||
auto backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
|
||||
MOBILEGL_ASSERT(backendTextureIt != TextureImpl::g_backendTextureObjects.end(),
|
||||
"No backend texture found while framebuffer reports texture attachment.");
|
||||
GLuint backendTexId = backendTextureIt->second->GetBackendTextureId();
|
||||
@@ -944,7 +950,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
"Attachment texture level mismatch between GLES and state object.");
|
||||
} else if (attachmentObject.IsRenderbuffer()) {
|
||||
const auto& renderbufferObject = attachmentObject.GetRenderbuffer();
|
||||
auto backendRboIt = RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject);
|
||||
auto backendRboIt =
|
||||
RenderbufferImpl::g_backendRenderbufferObjects.find(renderbufferObject.get());
|
||||
MOBILEGL_ASSERT(
|
||||
backendRboIt != RenderbufferImpl::g_backendRenderbufferObjects.end(),
|
||||
"No backend renderbuffer found while framebuffer reports renderbuffer attachment.");
|
||||
@@ -975,14 +982,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return glBackendReadBuffer;
|
||||
}
|
||||
|
||||
UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>>
|
||||
StateBackendObjectRegistry<MG_State::GLState::FramebufferObject, BackendFramebufferObject>
|
||||
g_backendFramebufferObjects;
|
||||
Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions = {0};
|
||||
} // namespace FramebufferImpl
|
||||
|
||||
namespace PrgramImpl {
|
||||
UnorderedMap<SharedPtr<MG_State::GLState::ProgramObject>, SharedPtr<BackendProgramObjectImpl>>
|
||||
g_backendProgramObjects;
|
||||
StateBackendObjectRegistry<MG_State::GLState::ProgramObject, BackendProgramObjectImpl> g_backendProgramObjects;
|
||||
|
||||
BackendProgramObjectImpl::BackendProgramObjectImpl() {
|
||||
#ifdef TRACY_ENABLE
|
||||
@@ -1008,7 +1014,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
}
|
||||
|
||||
void BackendProgramObjectImpl::SyncToBackend(SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject) {
|
||||
void BackendProgramObjectImpl::SyncToBackend(
|
||||
const SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
@@ -1161,7 +1168,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
MGLOG_D("Program sync completed. backend ID %u", m_backendProgramId);
|
||||
}
|
||||
|
||||
void BackendProgramObjectImpl::Use() {
|
||||
void BackendProgramObjectImpl::Use() const {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
@@ -1184,7 +1191,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
}
|
||||
|
||||
void BackendSamplerObject::SyncToBackend(SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject) {
|
||||
void BackendSamplerObject::SyncToBackend(
|
||||
const SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject) {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
@@ -1210,22 +1218,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#define SYNC_SAMPLER_PARAM_IF_CHANGED(internalName, glName, type) \
|
||||
if (m_cacheSamplerParameters.internalName != samplerParams.internalName) { \
|
||||
g_GLESFuncs.glSamplerParameteri(m_backendSamplerId, glName, \
|
||||
MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)); \
|
||||
(GLint)MG_Util::ConvertSampler##type##ToGLEnum(samplerParams.internalName)); \
|
||||
m_cacheSamplerParameters.internalName = samplerParams.internalName; \
|
||||
}
|
||||
|
||||
if (m_cacheSamplerParameters.minFilter != samplerParams.minFilter ||
|
||||
m_cacheSamplerParameters.mipmapMode != samplerParams.mipmapMode) {
|
||||
g_GLESFuncs.glSamplerParameteri(
|
||||
m_backendSamplerId, GL_TEXTURE_MIN_FILTER,
|
||||
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.minFilter, samplerParams.mipmapMode));
|
||||
g_GLESFuncs.glSamplerParameteri(m_backendSamplerId, GL_TEXTURE_MIN_FILTER,
|
||||
(GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(
|
||||
samplerParams.minFilter, samplerParams.mipmapMode));
|
||||
m_cacheSamplerParameters.minFilter = samplerParams.minFilter;
|
||||
m_cacheSamplerParameters.mipmapMode = samplerParams.mipmapMode;
|
||||
}
|
||||
if (m_cacheSamplerParameters.magFilter != samplerParams.magFilter) {
|
||||
g_GLESFuncs.glSamplerParameteri(
|
||||
m_backendSamplerId, GL_TEXTURE_MAG_FILTER,
|
||||
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.magFilter, SamplerMipmapMode::None));
|
||||
(GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(samplerParams.magFilter, SamplerMipmapMode::None));
|
||||
m_cacheSamplerParameters.magFilter = samplerParams.magFilter;
|
||||
}
|
||||
|
||||
@@ -1256,7 +1264,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
g_boundSamplersCache[unit] = this;
|
||||
}
|
||||
|
||||
Uint BackendSamplerObject::GetBackendSamplerId() {
|
||||
Uint BackendSamplerObject::GetBackendSamplerId() const {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
@@ -1271,8 +1279,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
|
||||
Array<BackendSamplerObject*, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS> g_boundSamplersCache;
|
||||
UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>>
|
||||
g_backendSamplerObjects;
|
||||
StateBackendObjectRegistry<MG_State::GLState::SamplerObject, BackendSamplerObject> g_backendSamplerObjects;
|
||||
} // namespace SamplerImpl
|
||||
|
||||
namespace RenderbufferImpl {
|
||||
@@ -1287,7 +1294,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
}
|
||||
|
||||
void BackendRenderbufferObject::Bind() {
|
||||
void BackendRenderbufferObject::Bind() const {
|
||||
#ifdef TRACY_ENABLE
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
@@ -1334,9 +1341,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
MGLOG_D("RBO %u sync completed. backend ID %u", stateRBOObject->GetExternalIndex(), m_backendRBOId);
|
||||
}
|
||||
|
||||
UnorderedMap<SharedPtr<MG_State::GLState::RenderbufferObject>, SharedPtr<BackendRenderbufferObject>>
|
||||
StateBackendObjectRegistry<MG_State::GLState::RenderbufferObject, BackendRenderbufferObject>
|
||||
g_backendRenderbufferObjects;
|
||||
} // namespace RenderbufferImpl
|
||||
|
||||
namespace Utils {} // namespace Utils
|
||||
} // namespace MobileGL::MG_Backend::DirectGLES
|
||||
|
||||
@@ -15,19 +15,113 @@
|
||||
#include <MG_State/GLState/Core.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectGLES {
|
||||
template <typename StateObject, typename BackendObject>
|
||||
class StateBackendObjectRegistry {
|
||||
public:
|
||||
using StatePtr = SharedPtr<StateObject>;
|
||||
using StateWeakPtr = std::weak_ptr<StateObject>;
|
||||
using BackendPtr = SharedPtr<BackendObject>;
|
||||
using BackendMap = UnorderedMap<StateObject*, BackendPtr>;
|
||||
using StateRefMap = UnorderedMap<StateObject*, StateWeakPtr>;
|
||||
using iterator = typename BackendMap::iterator;
|
||||
using const_iterator = typename BackendMap::const_iterator;
|
||||
|
||||
BackendPtr& GetOrCreate(const StatePtr& stateObj) {
|
||||
MOBILEGL_ASSERT(stateObj != nullptr, "State object must not be null");
|
||||
|
||||
auto* key = stateObj.get();
|
||||
auto trackedStateIt = m_stateRefs.find(key);
|
||||
if (trackedStateIt != m_stateRefs.end() && trackedStateIt->second.expired()) {
|
||||
EraseByKey(key);
|
||||
}
|
||||
m_stateRefs[key] = stateObj;
|
||||
return m_backendObjects[key];
|
||||
}
|
||||
|
||||
iterator find(StateObject* stateObj) {
|
||||
if (!IsAlive(stateObj)) {
|
||||
EraseByKey(stateObj);
|
||||
return m_backendObjects.end();
|
||||
}
|
||||
return m_backendObjects.find(stateObj);
|
||||
}
|
||||
|
||||
const_iterator find(StateObject* stateObj) const {
|
||||
return const_cast<StateBackendObjectRegistry*>(this)->find(stateObj);
|
||||
}
|
||||
|
||||
iterator end() { return m_backendObjects.end(); }
|
||||
const_iterator end() const { return m_backendObjects.end(); }
|
||||
|
||||
void CollectGarbageIfNeeded() {
|
||||
++m_gcTick;
|
||||
if (m_gcTick < kGCInterval) {
|
||||
return;
|
||||
}
|
||||
CollectGarbage();
|
||||
m_gcTick = 0;
|
||||
}
|
||||
|
||||
void CollectGarbageNow() { CollectGarbage(); }
|
||||
|
||||
private:
|
||||
bool IsAlive(StateObject* stateObj) const {
|
||||
const auto trackedStateIt = m_stateRefs.find(stateObj);
|
||||
if (trackedStateIt == m_stateRefs.end()) {
|
||||
return false;
|
||||
}
|
||||
return !trackedStateIt->second.expired();
|
||||
}
|
||||
|
||||
void EraseByKey(StateObject* stateObj) {
|
||||
m_stateRefs.erase(stateObj);
|
||||
m_backendObjects.erase(stateObj);
|
||||
}
|
||||
|
||||
void CollectGarbage() {
|
||||
if (m_isCollecting) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_isCollecting = true;
|
||||
|
||||
Vector<StateObject*> staleKeys;
|
||||
staleKeys.reserve(m_stateRefs.size());
|
||||
for (const auto& [stateKey, stateWeakRef] : m_stateRefs) {
|
||||
if (stateWeakRef.expired()) {
|
||||
staleKeys.push_back(stateKey);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto* stateKey : staleKeys) {
|
||||
m_stateRefs.erase(stateKey);
|
||||
m_backendObjects.erase(stateKey);
|
||||
}
|
||||
|
||||
m_isCollecting = false;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr Uint32 kGCInterval = 1024;
|
||||
StateRefMap m_stateRefs;
|
||||
BackendMap m_backendObjects;
|
||||
Uint32 m_gcTick = 0;
|
||||
Bool m_isCollecting = false;
|
||||
};
|
||||
|
||||
namespace BufferImpl {
|
||||
const GLenum TempBufferTarget = GL_ARRAY_BUFFER;
|
||||
class BackendBufferObject {
|
||||
public:
|
||||
BackendBufferObject();
|
||||
void SyncToBackend(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
||||
Uint GetBackendBufferId() { return m_backendBufferId; }
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
||||
Uint GetBackendBufferId() const { return m_backendBufferId; }
|
||||
void Bind(GLenum target = TempBufferTarget);
|
||||
|
||||
private:
|
||||
void SyncToBackend_glBufferData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
||||
void SyncToBackend_glBufferSubData(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
||||
void SyncToBackend_glMapBufferRange(SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject,
|
||||
void SyncToBackend_glBufferData(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
||||
void SyncToBackend_glBufferSubData(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject);
|
||||
void SyncToBackend_glMapBufferRange(const SharedPtr<MG_State::GLState::BufferObject>& stateBufferObject,
|
||||
Bool invalidate = true, Bool unsynchronized = true);
|
||||
|
||||
Uint m_backendBufferId = 0;
|
||||
@@ -36,21 +130,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
};
|
||||
|
||||
extern BackendBufferObject* g_boundVertexBufferObject;
|
||||
extern UnorderedMap<SharedPtr<MG_State::GLState::BufferObject>, SharedPtr<BackendBufferObject>>
|
||||
g_backendBufferObjects;
|
||||
extern StateBackendObjectRegistry<MG_State::GLState::BufferObject, BackendBufferObject> g_backendBufferObjects;
|
||||
} // namespace BufferImpl
|
||||
|
||||
namespace VertexArrayImpl {
|
||||
class BackendVertexArrayObject {
|
||||
public:
|
||||
BackendVertexArrayObject();
|
||||
void SyncToBackend(SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject);
|
||||
Uint GetBackendVertexArrayId() { return m_backendVAOId; }
|
||||
void Bind();
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject);
|
||||
Uint GetBackendVertexArrayId() const { return m_backendVAOId; }
|
||||
void Bind() const;
|
||||
|
||||
private:
|
||||
void BindAttributeBuffer(Uint index, const MG_State::GLState::VertexAttribute& attrib);
|
||||
|
||||
Uint m_backendVAOId = 0;
|
||||
Bool m_isInitialized = false;
|
||||
Uint16 m_syncedIndexBufferVersion = 0;
|
||||
@@ -58,7 +149,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
m_syncedAttributeVersions;
|
||||
};
|
||||
|
||||
extern UnorderedMap<SharedPtr<MG_State::GLState::VertexArrayObject>, SharedPtr<BackendVertexArrayObject>>
|
||||
extern StateBackendObjectRegistry<MG_State::GLState::VertexArrayObject, BackendVertexArrayObject>
|
||||
g_backendVertexArrayObjects;
|
||||
} // namespace VertexArrayImpl
|
||||
|
||||
@@ -92,11 +183,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
class BackendTextureObject {
|
||||
public:
|
||||
BackendTextureObject();
|
||||
void SyncMipmapsToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||
void SyncBuiltinSamplerToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||
void SyncTextureParamsToBackend(SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||
void SyncMipmapsToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||
void SyncBuiltinSamplerToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||
void SyncTextureParamsToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||
void Bind(GLenum target, Uint unit = TempTextureUnit);
|
||||
Uint GetBackendTextureId();
|
||||
Uint GetBackendTextureId() const;
|
||||
|
||||
private:
|
||||
Uint m_backendTextureId = 0;
|
||||
@@ -113,7 +204,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
void ActivateTextureUnit(Uint unit);
|
||||
void UnbindTexture(Uint unit, GLenum target);
|
||||
extern UnorderedMap<SharedPtr<MG_State::GLState::ITextureObject>, SharedPtr<BackendTextureObject>>
|
||||
extern StateBackendObjectRegistry<MG_State::GLState::ITextureObject, BackendTextureObject>
|
||||
g_backendTextureObjects;
|
||||
extern Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>,
|
||||
MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
|
||||
@@ -125,13 +216,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
class BackendFramebufferObject {
|
||||
public:
|
||||
BackendFramebufferObject();
|
||||
void SyncToBackend(SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
|
||||
FramebufferTarget asTarget);
|
||||
Uint GetBackendFramebufferId() { return m_backendFBOId; }
|
||||
void Bind(FramebufferTarget target);
|
||||
bool SyncAttachmentObject(GLenum glFBOTarget,
|
||||
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
|
||||
GLenum glBackendAttachment);
|
||||
Uint GetBackendFramebufferId() const { return m_backendFBOId; }
|
||||
void Bind(FramebufferTarget target) const;
|
||||
// FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index);
|
||||
GLenum GetBackendAttachmentType(FramebufferAttachmentType frontendAtt) const;
|
||||
|
||||
@@ -159,7 +247,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
FramebufferObject::FramebufferAttachmentVersionArray m_syncedFrontendAttachmentVersions = {0};
|
||||
};
|
||||
|
||||
extern UnorderedMap<SharedPtr<MG_State::GLState::FramebufferObject>, SharedPtr<BackendFramebufferObject>>
|
||||
extern StateBackendObjectRegistry<MG_State::GLState::FramebufferObject, BackendFramebufferObject>
|
||||
g_backendFramebufferObjects;
|
||||
extern Array<Uint16, SizeT(FramebufferTarget::FramebufferTargetCount)> g_fboBindVersions;
|
||||
} // namespace FramebufferImpl
|
||||
@@ -169,8 +257,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
public:
|
||||
BackendProgramObjectImpl();
|
||||
~BackendProgramObjectImpl();
|
||||
void SyncToBackend(SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject);
|
||||
void Use();
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject);
|
||||
void Use() const;
|
||||
Uint GetBackendProgramId() const { return m_backendProgramId; }
|
||||
Uint GetBackendGlobalUBOId() const { return m_backendGlobalUBOId; }
|
||||
|
||||
@@ -180,7 +268,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
Bool m_isInitialized = false;
|
||||
};
|
||||
|
||||
extern UnorderedMap<SharedPtr<MG_State::GLState::ProgramObject>, SharedPtr<BackendProgramObjectImpl>>
|
||||
extern StateBackendObjectRegistry<MG_State::GLState::ProgramObject, BackendProgramObjectImpl>
|
||||
g_backendProgramObjects;
|
||||
} // namespace PrgramImpl
|
||||
|
||||
@@ -188,9 +276,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
class BackendSamplerObject {
|
||||
public:
|
||||
BackendSamplerObject();
|
||||
void SyncToBackend(SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject);
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject);
|
||||
void Bind(Uint unit);
|
||||
Uint GetBackendSamplerId();
|
||||
Uint GetBackendSamplerId() const;
|
||||
|
||||
private:
|
||||
Uint m_backendSamplerId = 0;
|
||||
@@ -203,7 +291,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
extern Array<BackendSamplerObject*, MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
|
||||
g_boundSamplersCache;
|
||||
extern UnorderedMap<SharedPtr<MG_State::GLState::SamplerObject>, SharedPtr<BackendSamplerObject>>
|
||||
extern StateBackendObjectRegistry<MG_State::GLState::SamplerObject, BackendSamplerObject>
|
||||
g_backendSamplerObjects;
|
||||
} // namespace SamplerImpl
|
||||
|
||||
@@ -212,8 +300,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
public:
|
||||
BackendRenderbufferObject();
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::RenderbufferObject>& stateRBOObject);
|
||||
Uint GetBackendRenderbufferId() { return m_backendRBOId; }
|
||||
void Bind();
|
||||
Uint GetBackendRenderbufferId() const { return m_backendRBOId; }
|
||||
void Bind() const;
|
||||
|
||||
private:
|
||||
Uint m_backendRBOId = 0;
|
||||
@@ -223,7 +311,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
Int m_cacheHeight = 0;
|
||||
};
|
||||
|
||||
extern UnorderedMap<SharedPtr<MG_State::GLState::RenderbufferObject>, SharedPtr<BackendRenderbufferObject>>
|
||||
extern StateBackendObjectRegistry<MG_State::GLState::RenderbufferObject, BackendRenderbufferObject>
|
||||
g_backendRenderbufferObjects;
|
||||
} // namespace RenderbufferImpl
|
||||
} // namespace MobileGL::MG_Backend::DirectGLES
|
||||
|
||||
@@ -19,10 +19,6 @@
|
||||
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectGLES {
|
||||
namespace BufferImpl {} // namespace BufferImpl
|
||||
|
||||
namespace VertexArrayImpl {} // namespace VertexArrayImpl
|
||||
|
||||
namespace TextureImpl {
|
||||
void GenerateTextureFormatInfo(TextureInternalFormat internalFormat, GLenum* outInternalFormat,
|
||||
GLenum* outFormat, GLenum* outType) {
|
||||
@@ -36,9 +32,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
outInternalFormat, outFormat, outType);
|
||||
}
|
||||
} // namespace TextureImpl
|
||||
|
||||
namespace FramebufferImpl {} // namespace FramebufferImpl
|
||||
|
||||
namespace PrgramImpl {
|
||||
String ProcessOutColorLocations(const String& glslCode) {
|
||||
#ifdef TRACY_ENABLE
|
||||
@@ -166,7 +159,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return GL_UNIFORM_BUFFER_BINDING;
|
||||
|
||||
case GL_FRAMEBUFFER:
|
||||
return GL_FRAMEBUFFER_BINDING;
|
||||
case GL_DRAW_FRAMEBUFFER:
|
||||
return GL_DRAW_FRAMEBUFFER_BINDING;
|
||||
case GL_READ_FRAMEBUFFER:
|
||||
@@ -176,7 +168,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return GL_RENDERBUFFER_BINDING;
|
||||
|
||||
case GL_VERTEX_ARRAY:
|
||||
return GL_VERTEX_ARRAY_BINDING;
|
||||
case GL_VERTEX_ARRAY_BINDING:
|
||||
return GL_VERTEX_ARRAY_BINDING;
|
||||
|
||||
|
||||
@@ -14,15 +14,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
namespace DebugImpl {
|
||||
class ErrorLopper {
|
||||
public:
|
||||
void Loop(std::function<void(GLenum)>);
|
||||
void Clear();
|
||||
static void Loop(const std::function<void(GLenum)>&);
|
||||
static void Clear();
|
||||
ErrorLopper();
|
||||
~ErrorLopper();
|
||||
};
|
||||
|
||||
class OpenGLScopeMarker {
|
||||
public:
|
||||
explicit OpenGLScopeMarker(String scopeName);
|
||||
explicit OpenGLScopeMarker(const String& scopeName);
|
||||
~OpenGLScopeMarker();
|
||||
};
|
||||
} // namespace DebugImpl
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
auto nativeWindow = reinterpret_cast<NativeWindowType>(m_windowHandle.Handle);
|
||||
|
||||
pVulkanRenderer = MakeUnique<MG_Backend::DirectVulkan::VulkanRenderer>(nativeWindow);
|
||||
MOBILEGL_ASSERT(pVulkanRenderer != nullptr, "InitWindowSurface: VulkanRenderer creation failed");
|
||||
pVulkanRenderer->Initialize();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -17,165 +17,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) {}
|
||||
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {}
|
||||
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) {}
|
||||
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) {
|
||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElementsBaseVertex called with null VulkanRenderer");
|
||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawElementsBaseVertex called with null GL context");
|
||||
|
||||
if (count < 0) {
|
||||
MGLOG_W("DrawElementsBaseVertex skipped: count (%d) must be non-negative", count);
|
||||
return;
|
||||
}
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
if (mode != GL_TRIANGLES) {
|
||||
MGLOG_W("DrawElementsBaseVertex skipped: primitive mode %u is not supported yet", mode);
|
||||
return;
|
||||
}
|
||||
|
||||
SizeT indexSize = 0;
|
||||
switch (type) {
|
||||
case GL_UNSIGNED_SHORT:
|
||||
indexSize = sizeof(Uint16);
|
||||
break;
|
||||
case GL_UNSIGNED_INT:
|
||||
indexSize = sizeof(Uint32);
|
||||
break;
|
||||
default:
|
||||
MGLOG_W("DrawElementsBaseVertex skipped: index type %u is not supported yet", type);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!vao) {
|
||||
MGLOG_W("DrawElementsBaseVertex skipped: no bound VAO");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject();
|
||||
if (!indexBuffer) {
|
||||
MGLOG_W("DrawElementsBaseVertex skipped: no bound ELEMENT_ARRAY_BUFFER");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto indexData = indexBuffer->GetDataReadOnly();
|
||||
if (!indexData || indexData->empty()) {
|
||||
MGLOG_W("DrawElementsBaseVertex skipped: ELEMENT_ARRAY_BUFFER has no data");
|
||||
return;
|
||||
}
|
||||
|
||||
const SizeT byteOffset = reinterpret_cast<SizeT>(indices);
|
||||
const SizeT requiredBytes = static_cast<SizeT>(count) * indexSize;
|
||||
if (byteOffset + requiredBytes > indexBuffer->GetSize()) {
|
||||
MGLOG_W("DrawElementsBaseVertex skipped: index range out of bounds (offset=%zu, size=%zu, buffer=%zu)",
|
||||
byteOffset, requiredBytes, indexBuffer->GetSize());
|
||||
return;
|
||||
}
|
||||
|
||||
DrawElementPayload payload{};
|
||||
payload.drawArray.mode = mode;
|
||||
payload.drawArray.first = 0;
|
||||
payload.drawArray.count = count;
|
||||
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
|
||||
payload.drawArray.vertexArray = vao.get();
|
||||
payload.indexType = type;
|
||||
payload.indexByteOffset = byteOffset;
|
||||
payload.baseVertex = basevertex;
|
||||
|
||||
pVulkanRenderer->DrawElements(payload);
|
||||
}
|
||||
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) {}
|
||||
|
||||
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
||||
GLsizei drawcount, const GLint* basevertex) {
|
||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsBaseVertex called with null VulkanRenderer");
|
||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElementsBaseVertex called with null GL context");
|
||||
GLsizei drawcount, const GLint* basevertex) {}
|
||||
|
||||
if (drawcount < 0) {
|
||||
MGLOG_W("MultiDrawElementsBaseVertex skipped: drawcount (%d) must be non-negative", drawcount);
|
||||
return;
|
||||
}
|
||||
if (drawcount == 0) {
|
||||
return;
|
||||
}
|
||||
if (!count || !indices || !basevertex) {
|
||||
MGLOG_W("MultiDrawElementsBaseVertex skipped: count/indices/basevertex pointer is null");
|
||||
return;
|
||||
}
|
||||
if (mode != GL_TRIANGLES) {
|
||||
MGLOG_W("MultiDrawElementsBaseVertex skipped: primitive mode %u is not supported yet", mode);
|
||||
return;
|
||||
}
|
||||
|
||||
SizeT indexSize = 0;
|
||||
switch (type) {
|
||||
case GL_UNSIGNED_SHORT:
|
||||
indexSize = sizeof(Uint16);
|
||||
break;
|
||||
case GL_UNSIGNED_INT:
|
||||
indexSize = sizeof(Uint32);
|
||||
break;
|
||||
default:
|
||||
MGLOG_W("MultiDrawElementsBaseVertex skipped: index type %u is not supported yet", type);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!vao) {
|
||||
MGLOG_W("MultiDrawElementsBaseVertex skipped: no bound VAO");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject();
|
||||
if (!indexBuffer) {
|
||||
MGLOG_W("MultiDrawElementsBaseVertex skipped: no bound ELEMENT_ARRAY_BUFFER");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto indexData = indexBuffer->GetDataReadOnly();
|
||||
if (!indexData || indexData->empty()) {
|
||||
MGLOG_W("MultiDrawElementsBaseVertex skipped: ELEMENT_ARRAY_BUFFER has no data");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||
Vector<DrawElementPayload> payloads;
|
||||
payloads.reserve(static_cast<SizeT>(drawcount));
|
||||
for (GLsizei i = 0; i < drawcount; ++i) {
|
||||
if (count[i] < 0) {
|
||||
MGLOG_W("MultiDrawElementsBaseVertex skipped: count[%d] (%d) must be non-negative", i, count[i]);
|
||||
return;
|
||||
}
|
||||
if (count[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const SizeT byteOffset = reinterpret_cast<SizeT>(indices[i]);
|
||||
const SizeT requiredBytes = static_cast<SizeT>(count[i]) * indexSize;
|
||||
if (byteOffset + requiredBytes > indexBuffer->GetSize()) {
|
||||
MGLOG_W("MultiDrawElementsBaseVertex skipped: draw[%d] index range out of bounds (offset=%zu, "
|
||||
"size=%zu, buffer=%zu)",
|
||||
i, byteOffset, requiredBytes, indexBuffer->GetSize());
|
||||
return;
|
||||
}
|
||||
|
||||
DrawElementPayload payload{};
|
||||
payload.drawArray.mode = mode;
|
||||
payload.drawArray.first = 0;
|
||||
payload.drawArray.count = count[i];
|
||||
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
|
||||
payload.drawArray.vertexArray = vao.get();
|
||||
payload.indexType = type;
|
||||
payload.indexByteOffset = byteOffset;
|
||||
payload.baseVertex = basevertex[i];
|
||||
payloads.push_back(payload);
|
||||
}
|
||||
|
||||
if (payloads.empty()) {
|
||||
return;
|
||||
}
|
||||
pVulkanRenderer->MultiDrawElements(payloads);
|
||||
}
|
||||
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {}
|
||||
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {}
|
||||
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||
@@ -206,180 +52,44 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElements called with null VulkanRenderer");
|
||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElements called with null GL context");
|
||||
|
||||
if (drawcount < 0) {
|
||||
MGLOG_W("MultiDrawElements skipped: drawcount (%d) must be non-negative", drawcount);
|
||||
return;
|
||||
}
|
||||
if (drawcount == 0) {
|
||||
return;
|
||||
}
|
||||
if (!count || !indices) {
|
||||
MGLOG_W("MultiDrawElements skipped: count/indices pointer is null");
|
||||
return;
|
||||
}
|
||||
if (mode != GL_TRIANGLES) {
|
||||
MGLOG_W("MultiDrawElements skipped: primitive mode %u is not supported yet", mode);
|
||||
return;
|
||||
}
|
||||
|
||||
SizeT indexSize = 0;
|
||||
switch (type) {
|
||||
case GL_UNSIGNED_SHORT:
|
||||
indexSize = sizeof(Uint16);
|
||||
break;
|
||||
case GL_UNSIGNED_INT:
|
||||
indexSize = sizeof(Uint32);
|
||||
break;
|
||||
default:
|
||||
MGLOG_W("MultiDrawElements skipped: index type %u is not supported yet", type);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!vao) {
|
||||
MGLOG_W("MultiDrawElements skipped: no bound VAO");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject();
|
||||
if (!indexBuffer) {
|
||||
MGLOG_W("MultiDrawElements skipped: no bound ELEMENT_ARRAY_BUFFER");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto indexData = indexBuffer->GetDataReadOnly();
|
||||
if (!indexData || indexData->empty()) {
|
||||
MGLOG_W("MultiDrawElements skipped: ELEMENT_ARRAY_BUFFER has no data");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||
Vector<DrawElementPayload> payloads;
|
||||
payloads.reserve(static_cast<SizeT>(drawcount));
|
||||
Vector<DrawElementCmd> cmds;
|
||||
cmds.reserve(static_cast<SizeT>(drawcount));
|
||||
for (GLsizei i = 0; i < drawcount; ++i) {
|
||||
if (count[i] < 0) {
|
||||
MGLOG_W("MultiDrawElements skipped: count[%d] (%d) must be non-negative", i, count[i]);
|
||||
return;
|
||||
}
|
||||
if (count[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto byteOffset = reinterpret_cast<SizeT>(indices[i]);
|
||||
const SizeT requiredBytes = static_cast<SizeT>(count[i]) * indexSize;
|
||||
if (byteOffset + requiredBytes > indexBuffer->GetSize()) {
|
||||
MGLOG_W("MultiDrawElements skipped: draw[%d] index range out of bounds (offset=%zu, size=%zu, "
|
||||
"buffer=%zu)",
|
||||
i, byteOffset, requiredBytes, indexBuffer->GetSize());
|
||||
return;
|
||||
}
|
||||
|
||||
DrawElementPayload payload{};
|
||||
payload.drawArray.mode = mode;
|
||||
payload.drawArray.first = 0;
|
||||
payload.drawArray.count = count[i];
|
||||
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
|
||||
payload.drawArray.vertexArray = vao.get();
|
||||
DrawElementCmd payload{};
|
||||
payload.mode = mode;
|
||||
payload.first = 0;
|
||||
payload.count = count[i];
|
||||
payload.indexType = type;
|
||||
payload.indexByteOffset = byteOffset;
|
||||
payloads.push_back(payload);
|
||||
payload.indexByteOffset = reinterpret_cast<SizeT>(indices[i]);
|
||||
cmds.push_back(payload);
|
||||
}
|
||||
|
||||
if (payloads.empty()) {
|
||||
if (cmds.empty()) {
|
||||
return;
|
||||
}
|
||||
pVulkanRenderer->MultiDrawElements(payloads);
|
||||
pVulkanRenderer->MultiDrawElements(cmds);
|
||||
}
|
||||
|
||||
void Clear(GLbitfield mask) {
|
||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Clear called with null VulkanRenderer");
|
||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::Clear called with null GL context");
|
||||
|
||||
const auto& drawFboSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
|
||||
const auto drawFbo = drawFboSlot.GetBoundObject();
|
||||
const auto defaultFboInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
||||
const auto defaultFbo = defaultFboInfo ? defaultFboInfo->defaultFBO : nullptr;
|
||||
const Bool isDefaultFboTarget = (drawFbo == defaultFbo) || (drawFbo == nullptr && defaultFbo != nullptr);
|
||||
Uint drawFboExternalIndex = 0;
|
||||
if (drawFbo) {
|
||||
drawFboExternalIndex = drawFbo->GetExternalIndex();
|
||||
} else if (defaultFbo) {
|
||||
drawFboExternalIndex = defaultFbo->GetExternalIndex();
|
||||
}
|
||||
|
||||
const auto& clearColor = MG_State::pGLContext->GetClearColor();
|
||||
const auto clearDepth = MG_State::pGLContext->GetClearDepth();
|
||||
const auto clearStencil = static_cast<Uint32>(MG_State::pGLContext->GetClearStencil());
|
||||
pVulkanRenderer->RequestClear(mask, clearColor, clearDepth, clearStencil, drawFboExternalIndex,
|
||||
isDefaultFboTarget);
|
||||
pVulkanRenderer->Clear(mask);
|
||||
}
|
||||
|
||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
|
||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElements called with null VulkanRenderer");
|
||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawElements called with null GL context");
|
||||
|
||||
if (count < 0) {
|
||||
MGLOG_W("DrawElements skipped: count (%d) must be non-negative", count);
|
||||
return;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode != GL_TRIANGLES) {
|
||||
MGLOG_W("DrawElements skipped: primitive mode %u is not supported yet", mode);
|
||||
return;
|
||||
}
|
||||
|
||||
SizeT indexSize = 0;
|
||||
switch (type) {
|
||||
case GL_UNSIGNED_SHORT:
|
||||
indexSize = sizeof(Uint16);
|
||||
break;
|
||||
case GL_UNSIGNED_INT:
|
||||
indexSize = sizeof(Uint32);
|
||||
break;
|
||||
default:
|
||||
MGLOG_W("DrawElements skipped: index type %u is not supported yet", type);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!vao) {
|
||||
MGLOG_W("DrawElements skipped: no bound VAO");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto indexBuffer = vao->GetIndexBufferBindingSlot().GetBoundObject();
|
||||
if (!indexBuffer) {
|
||||
MGLOG_W("DrawElements skipped: no bound ELEMENT_ARRAY_BUFFER");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto indexData = indexBuffer->GetDataReadOnly();
|
||||
if (!indexData || indexData->empty()) {
|
||||
MGLOG_W("DrawElements skipped: ELEMENT_ARRAY_BUFFER has no data");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto byteOffset = reinterpret_cast<SizeT>(indices);
|
||||
const SizeT requiredBytes = static_cast<SizeT>(count) * indexSize;
|
||||
if (byteOffset + requiredBytes > indexBuffer->GetSize()) {
|
||||
MGLOG_W("DrawElements skipped: index range out of bounds (offset=%zu, size=%zu, buffer=%zu)", byteOffset,
|
||||
requiredBytes, indexBuffer->GetSize());
|
||||
return;
|
||||
}
|
||||
|
||||
DrawElementPayload payload{};
|
||||
payload.drawArray.mode = mode;
|
||||
payload.drawArray.first = 0;
|
||||
payload.drawArray.count = count;
|
||||
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||
payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr;
|
||||
payload.drawArray.vertexArray = vao.get();
|
||||
DrawElementCmd payload{};
|
||||
payload.mode = mode;
|
||||
payload.first = 0;
|
||||
payload.count = count;
|
||||
payload.indexType = type;
|
||||
payload.indexByteOffset = byteOffset;
|
||||
payload.indexByteOffset = reinterpret_cast<SizeT>(indices);
|
||||
|
||||
pVulkanRenderer->DrawElements(payload);
|
||||
}
|
||||
@@ -388,34 +98,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawArrays called with null VulkanRenderer");
|
||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawArrays called with null GL context");
|
||||
|
||||
if (first < 0) {
|
||||
MGLOG_W("DrawArrays skipped: first (%d) must be non-negative", first);
|
||||
return;
|
||||
}
|
||||
|
||||
if (count < 0) {
|
||||
MGLOG_W("DrawArrays skipped: count (%d) must be non-negative", count);
|
||||
return;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode != GL_TRIANGLES) {
|
||||
MGLOG_W("DrawArrays skipped: primitive mode %u is not supported yet", mode);
|
||||
return;
|
||||
}
|
||||
|
||||
DrawArrayPayload payload{};
|
||||
DrawArrayCmd payload{};
|
||||
payload.mode = mode;
|
||||
payload.first = first;
|
||||
payload.count = count;
|
||||
const auto currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||
payload.program = currentProgram ? currentProgram.get() : nullptr;
|
||||
|
||||
const auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||
payload.vertexArray = vao ? vao.get() : nullptr;
|
||||
|
||||
pVulkanRenderer->DrawArrays(payload);
|
||||
}
|
||||
@@ -424,33 +110,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
GLint dstY1, GLbitfield mask, GLenum filter) {
|
||||
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::BlitFramebuffer called with null VulkanRenderer");
|
||||
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::BlitFramebuffer called with null GL context");
|
||||
|
||||
const auto& readFboSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
|
||||
const auto& drawFboSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
|
||||
const auto readFbo = readFboSlot.GetBoundObject();
|
||||
const auto drawFbo = drawFboSlot.GetBoundObject();
|
||||
const auto defaultFboInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
||||
const auto defaultFbo = defaultFboInfo ? defaultFboInfo->defaultFBO : nullptr;
|
||||
|
||||
const Bool readIsDefault = (readFbo == defaultFbo) || (readFbo == nullptr && defaultFbo != nullptr);
|
||||
const Bool drawIsDefault = (drawFbo == defaultFbo) || (drawFbo == nullptr && defaultFbo != nullptr);
|
||||
|
||||
Uint readFboExternalIndex = 0;
|
||||
if (readFbo) {
|
||||
readFboExternalIndex = readFbo->GetExternalIndex();
|
||||
} else if (defaultFbo) {
|
||||
readFboExternalIndex = defaultFbo->GetExternalIndex();
|
||||
}
|
||||
|
||||
Uint drawFboExternalIndex = 0;
|
||||
if (drawFbo) {
|
||||
drawFboExternalIndex = drawFbo->GetExternalIndex();
|
||||
} else if (defaultFbo) {
|
||||
drawFboExternalIndex = defaultFbo->GetExternalIndex();
|
||||
}
|
||||
|
||||
pVulkanRenderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter,
|
||||
readFboExternalIndex, drawFboExternalIndex, readIsDefault, drawIsDefault);
|
||||
pVulkanRenderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||
}
|
||||
|
||||
void Present() {
|
||||
|
||||
@@ -21,6 +21,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.renderPass, sizeof(payload.renderPass)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.subpass, sizeof(payload.subpass)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.topology, sizeof(payload.topology)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.cullMode, sizeof(payload.cullMode)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.frontFace, sizeof(payload.frontFace)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthTestEnable, sizeof(payload.depthTestEnable)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthWriteEnable, sizeof(payload.depthWriteEnable)));
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthCompareOp, sizeof(payload.depthCompareOp)));
|
||||
@@ -79,8 +81,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo raster{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO};
|
||||
raster.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
raster.cullMode = VK_CULL_MODE_NONE;
|
||||
raster.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||
raster.cullMode = payload.cullMode;
|
||||
raster.frontFace = payload.frontFace;
|
||||
raster.lineWidth = 1.0f;
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo ms{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO};
|
||||
|
||||
@@ -24,6 +24,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||
Uint32 subpass = 0;
|
||||
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
|
||||
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||
Bool depthTestEnable = false;
|
||||
Bool depthWriteEnable = false;
|
||||
VkCompareOp depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
|
||||
@@ -364,7 +364,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
auto& entry = m_cache[hash];
|
||||
entry.device = m_device;
|
||||
entry.hash = hash;
|
||||
auto& shaders = program.GetAttachedShaders();
|
||||
auto& spirv = program.GetGeneratedSpirv();
|
||||
|
||||
@@ -26,39 +26,35 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
};
|
||||
using CompileOptionFlags = Flags<CompileOptionBit>;
|
||||
using HashType = Uint64;
|
||||
struct BackendProgramObject {
|
||||
struct VkProgramObject {
|
||||
HashType hash = 0;
|
||||
VkDevice device = VK_NULL_HANDLE;
|
||||
Vector<VkPipelineShaderStageCreateInfo> stages;
|
||||
Vector<VkShaderModule> modules;
|
||||
static inline VkDevice s_device = VK_NULL_HANDLE;
|
||||
|
||||
BackendProgramObject() = default;
|
||||
BackendProgramObject(const BackendProgramObject&) = delete;
|
||||
BackendProgramObject& operator=(const BackendProgramObject&) = delete;
|
||||
BackendProgramObject(BackendProgramObject&& other) noexcept {
|
||||
VkProgramObject() = default;
|
||||
VkProgramObject(const VkProgramObject&) = delete;
|
||||
VkProgramObject& operator=(const VkProgramObject&) = delete;
|
||||
VkProgramObject(VkProgramObject&& other) noexcept {
|
||||
hash = other.hash;
|
||||
device = other.device;
|
||||
stages = std::move(other.stages);
|
||||
modules = std::move(other.modules);
|
||||
other.hash = 0;
|
||||
other.device = VK_NULL_HANDLE;
|
||||
}
|
||||
BackendProgramObject& operator=(BackendProgramObject&& other) noexcept {
|
||||
VkProgramObject& operator=(VkProgramObject&& other) noexcept {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
DestroyModules();
|
||||
stages.clear();
|
||||
hash = other.hash;
|
||||
device = other.device;
|
||||
stages = std::move(other.stages);
|
||||
modules = std::move(other.modules);
|
||||
other.hash = 0;
|
||||
other.device = VK_NULL_HANDLE;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~BackendProgramObject() {
|
||||
~VkProgramObject() {
|
||||
DestroyModules();
|
||||
stages.clear();
|
||||
}
|
||||
@@ -66,8 +62,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
private:
|
||||
void DestroyModules() {
|
||||
for (auto module : modules) {
|
||||
if (module != VK_NULL_HANDLE && device != VK_NULL_HANDLE) {
|
||||
vkDestroyShaderModule(device, module, nullptr);
|
||||
if (module != VK_NULL_HANDLE && s_device != VK_NULL_HANDLE) {
|
||||
vkDestroyShaderModule(s_device, module, nullptr);
|
||||
}
|
||||
}
|
||||
modules.clear();
|
||||
@@ -75,7 +71,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
};
|
||||
|
||||
explicit ProgramFactory(VkDevice device, const VulkanRendererConfig& config)
|
||||
: m_device(device), m_config(config) {}
|
||||
: m_device(device), m_config(config) {
|
||||
VkProgramObject::s_device = device;
|
||||
}
|
||||
~ProgramFactory();
|
||||
ProgramFactory(const ProgramFactory&) = delete;
|
||||
|
||||
@@ -87,7 +85,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
private:
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
UnorderedMap<HashType, BackendProgramObject> m_cache;
|
||||
UnorderedMap<HashType, VkProgramObject> m_cache;
|
||||
const VulkanRendererConfig& m_config;
|
||||
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
||||
};
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
#include "SwapchainObject.h"
|
||||
|
||||
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
|
||||
#include "MG_State/GLState/TextureState/TextureObject2D.h"
|
||||
|
||||
#if defined(__has_include)
|
||||
#if __has_include(<vulkan/vk_enum_string_helper.h>)
|
||||
#include <vulkan/vk_enum_string_helper.h>
|
||||
@@ -38,6 +41,40 @@ static const char* string_VkSurfaceTransformFlagBitsKHR(VkSurfaceTransformFlagBi
|
||||
#endif
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
namespace {
|
||||
Bool HasStencilComponent(VkFormat format) {
|
||||
return format == VK_FORMAT_D24_UNORM_S8_UINT || format == VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||
}
|
||||
|
||||
VkFormat FindSupportedDepthStencilFormat(VkPhysicalDevice physicalDevice) {
|
||||
const VkFormat candidates[] = {VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT,
|
||||
VK_FORMAT_D32_SFLOAT};
|
||||
for (VkFormat format : candidates) {
|
||||
VkFormatProperties props{};
|
||||
vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &props);
|
||||
if ((props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
|
||||
Uint32 FindMemoryType(VkPhysicalDevice physicalDevice, Uint32 typeFilter, VkMemoryPropertyFlags properties) {
|
||||
VkPhysicalDeviceMemoryProperties memProperties{};
|
||||
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
|
||||
|
||||
for (Uint32 i = 0; i < memProperties.memoryTypeCount; i++) {
|
||||
if ((typeFilter & (1 << i)) &&
|
||||
(memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
MOBILEGL_ASSERT(false, "Failed to find suitable memory type.");
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
SwapchainObject::SwapchainCapabilities SwapchainObject::GetSwapchainCapabilities(VkPhysicalDevice physicalDevice,
|
||||
VkSurfaceKHR surface) {
|
||||
SwapchainCapabilities swapchainCapabilities{};
|
||||
@@ -127,6 +164,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
createInfo.imageFormat = pickedSurfaceFormat.format;
|
||||
createInfo.imageColorSpace = pickedSurfaceFormat.colorSpace;
|
||||
createInfo.imageExtent = swapchainCaps.currentExtent;
|
||||
if (swapchainCaps.currentTransform == VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR ||
|
||||
swapchainCaps.currentTransform == VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) {
|
||||
std::swap(createInfo.imageExtent.width, createInfo.imageExtent.height);
|
||||
}
|
||||
|
||||
createInfo.imageArrayLayers = 1;
|
||||
const VkImageUsageFlags requiredImageUsage =
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
@@ -185,12 +227,133 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_imageLayouts.assign(imageCount, VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
|
||||
CreateImageViews(device);
|
||||
CreateDepthStencilResources(device, physicalDevice);
|
||||
|
||||
MGLOG_I("Swapchain created, extent = %dx%d, swapchain imageCount = %d", m_extent.width, m_extent.height,
|
||||
imageCount);
|
||||
|
||||
// Properly initialize Default FBO here
|
||||
auto& defaultFBOInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
||||
auto* colorTex = static_cast<MG_State::GLState::TextureObject2D*>(defaultFBOInfo->colorAttachment.get());
|
||||
colorTex->AllocateStorage(
|
||||
TextureUploadTarget::Texture2D, 0, {
|
||||
{(Int)createInfo.imageExtent.width, (Int)createInfo.imageExtent.height, 1},
|
||||
createInfo.imageExtent.width * (Int)createInfo.imageExtent.height * 4}); // TODO: 4 is format size
|
||||
TextureInternalFormat depthFormat = TextureInternalFormat::Depth24Stencil8;
|
||||
switch (m_depthStencilFormat) {
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||
depthFormat = TextureInternalFormat::Depth24Stencil8;
|
||||
break;
|
||||
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
||||
depthFormat = TextureInternalFormat::Depth32FStencil8;
|
||||
break;
|
||||
case VK_FORMAT_D32_SFLOAT:
|
||||
depthFormat = TextureInternalFormat::DepthComponent32F;
|
||||
break;
|
||||
default:
|
||||
depthFormat = TextureInternalFormat::Depth24Stencil8;
|
||||
break;
|
||||
}
|
||||
auto* depthTex = static_cast<MG_State::GLState::TextureObject2D*>(defaultFBOInfo->depthAttachment.get());
|
||||
depthTex->SetInternalFormat(depthFormat);
|
||||
depthTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, {
|
||||
{(Int)createInfo.imageExtent.width, (Int)createInfo.imageExtent.height, 1},
|
||||
createInfo.imageExtent.width * createInfo.imageExtent.width * 4}); // TODO: 4 is format size
|
||||
|
||||
}
|
||||
|
||||
void SwapchainObject::CreateDepthStencilResources(VkDevice device, VkPhysicalDevice physicalDevice) {
|
||||
DestroyDepthStencilResources(device);
|
||||
|
||||
const auto imageCount = static_cast<Uint32>(m_images.size());
|
||||
if (imageCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_depthStencilFormat = FindSupportedDepthStencilFormat(physicalDevice);
|
||||
MOBILEGL_ASSERT(m_depthStencilFormat != VK_FORMAT_UNDEFINED, "No supported depth/stencil format found.");
|
||||
|
||||
m_depthStencilImages.assign(imageCount, VK_NULL_HANDLE);
|
||||
m_depthStencilImageMemories.assign(imageCount, VK_NULL_HANDLE);
|
||||
m_depthStencilImageViews.assign(imageCount, VK_NULL_HANDLE);
|
||||
m_depthStencilImageLayouts.assign(imageCount, VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
|
||||
for (Uint32 i = 0; i < imageCount; ++i) {
|
||||
VkImageCreateInfo imageInfo{};
|
||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.extent.width = m_extent.width;
|
||||
imageInfo.extent.height = m_extent.height;
|
||||
imageInfo.extent.depth = 1;
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.arrayLayers = 1;
|
||||
imageInfo.format = m_depthStencilFormat;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VK_VERIFY(vkCreateImage(device, &imageInfo, nullptr, &m_depthStencilImages[i]), "vkCreateImage(depth)");
|
||||
|
||||
VkMemoryRequirements memRequirements{};
|
||||
vkGetImageMemoryRequirements(device, m_depthStencilImages[i], &memRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = memRequirements.size;
|
||||
allocInfo.memoryTypeIndex =
|
||||
FindMemoryType(physicalDevice, memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
VK_VERIFY(vkAllocateMemory(device, &allocInfo, nullptr, &m_depthStencilImageMemories[i]),
|
||||
"vkAllocateMemory(depth)");
|
||||
VK_VERIFY(vkBindImageMemory(device, m_depthStencilImages[i], m_depthStencilImageMemories[i], 0),
|
||||
"vkBindImageMemory(depth)");
|
||||
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = m_depthStencilImages[i];
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = m_depthStencilFormat;
|
||||
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
if (HasStencilComponent(m_depthStencilFormat)) {
|
||||
viewInfo.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
viewInfo.subresourceRange.baseMipLevel = 0;
|
||||
viewInfo.subresourceRange.levelCount = 1;
|
||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
viewInfo.subresourceRange.layerCount = 1;
|
||||
VK_VERIFY(vkCreateImageView(device, &viewInfo, nullptr, &m_depthStencilImageViews[i]),
|
||||
"vkCreateImageView(depth)");
|
||||
}
|
||||
}
|
||||
|
||||
void SwapchainObject::DestroyDepthStencilResources(VkDevice device) {
|
||||
for (auto view : m_depthStencilImageViews) {
|
||||
if (view != VK_NULL_HANDLE) {
|
||||
vkDestroyImageView(device, view, nullptr);
|
||||
}
|
||||
}
|
||||
m_depthStencilImageViews.clear();
|
||||
|
||||
for (auto image : m_depthStencilImages) {
|
||||
if (image != VK_NULL_HANDLE) {
|
||||
vkDestroyImage(device, image, nullptr);
|
||||
}
|
||||
}
|
||||
m_depthStencilImages.clear();
|
||||
|
||||
for (auto memory : m_depthStencilImageMemories) {
|
||||
if (memory != VK_NULL_HANDLE) {
|
||||
vkFreeMemory(device, memory, nullptr);
|
||||
}
|
||||
}
|
||||
m_depthStencilImageMemories.clear();
|
||||
m_depthStencilImageLayouts.clear();
|
||||
m_depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
|
||||
void SwapchainObject::Shutdown(VkDevice device) {
|
||||
DestroyDepthStencilResources(device);
|
||||
|
||||
for (auto imageView : m_imageViews) {
|
||||
vkDestroyImageView(device, imageView, nullptr);
|
||||
}
|
||||
@@ -221,6 +384,29 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_imageLayouts[index] = layout;
|
||||
}
|
||||
|
||||
VkImage SwapchainObject::GetDepthStencilImage(Uint32 index) const {
|
||||
MOBILEGL_ASSERT(index < m_depthStencilImages.size(), "Swapchain depth/stencil image index out of range");
|
||||
return m_depthStencilImages[index];
|
||||
}
|
||||
|
||||
VkImageView SwapchainObject::GetDepthStencilImageView(Uint32 index) const {
|
||||
MOBILEGL_ASSERT(index < m_depthStencilImageViews.size(),
|
||||
"Swapchain depth/stencil image view index out of range");
|
||||
return m_depthStencilImageViews[index];
|
||||
}
|
||||
|
||||
VkImageLayout SwapchainObject::GetDepthStencilImageLayout(Uint32 index) const {
|
||||
MOBILEGL_ASSERT(index < m_depthStencilImageLayouts.size(),
|
||||
"Swapchain depth/stencil image layout index out of range");
|
||||
return m_depthStencilImageLayouts[index];
|
||||
}
|
||||
|
||||
void SwapchainObject::SetDepthStencilImageLayout(Uint32 index, VkImageLayout layout) {
|
||||
MOBILEGL_ASSERT(index < m_depthStencilImageLayouts.size(),
|
||||
"Swapchain depth/stencil image layout index out of range");
|
||||
m_depthStencilImageLayouts[index] = layout;
|
||||
}
|
||||
|
||||
void SwapchainObject::CreateImageViews(VkDevice device) {
|
||||
m_imageViews.resize(m_images.size(), VK_NULL_HANDLE);
|
||||
for (SizeT i = 0; i < m_imageViews.size(); i++) {
|
||||
|
||||
@@ -38,6 +38,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkSurfaceTransformFlagBitsKHR GetPreTransform() const { return m_preTransform; }
|
||||
const Vector<VkImage>& GetImages() const { return m_images; }
|
||||
const Vector<VkImageView>& GetImageViews() const { return m_imageViews; }
|
||||
VkFormat GetDepthStencilFormat() const { return m_depthStencilFormat; }
|
||||
const Vector<VkImageView>& GetDepthStencilImageViews() const { return m_depthStencilImageViews; }
|
||||
VkImage GetDepthStencilImage(Uint32 index) const;
|
||||
VkImageView GetDepthStencilImageView(Uint32 index) const;
|
||||
VkImageLayout GetDepthStencilImageLayout(Uint32 index) const;
|
||||
void SetDepthStencilImageLayout(Uint32 index, VkImageLayout layout);
|
||||
VkImage GetImage(Uint32 index) const;
|
||||
VkImageLayout GetImageLayout(Uint32 index) const;
|
||||
void SetImageLayout(Uint32 index, VkImageLayout layout);
|
||||
@@ -45,6 +51,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
private:
|
||||
void CreateImageViews(VkDevice device);
|
||||
void CreateDepthStencilResources(VkDevice device, VkPhysicalDevice physicalDevice);
|
||||
void DestroyDepthStencilResources(VkDevice device);
|
||||
static constexpr VkPresentModeKHR s_desiredPresentModes[] {
|
||||
VK_PRESENT_MODE_MAILBOX_KHR,
|
||||
VK_PRESENT_MODE_IMMEDIATE_KHR,
|
||||
@@ -59,5 +67,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Vector<VkImage> m_images;
|
||||
Vector<VkImageView> m_imageViews;
|
||||
Vector<VkImageLayout> m_imageLayouts;
|
||||
|
||||
VkFormat m_depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
Vector<VkImage> m_depthStencilImages;
|
||||
Vector<VkDeviceMemory> m_depthStencilImageMemories;
|
||||
Vector<VkImageView> m_depthStencilImageViews;
|
||||
Vector<VkImageLayout> m_depthStencilImageLayouts;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -8,13 +8,52 @@
|
||||
|
||||
#include "UniformDescriptorBinder.h"
|
||||
|
||||
#include "VkFramebufferManager.h"
|
||||
#include "MG_State/GLState/Core.h"
|
||||
#include "MG_State/GLState/ProgramState/ProgramObject.h"
|
||||
#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h"
|
||||
#include "MG_Util/ShaderTranspiler/Types.h"
|
||||
#include <limits>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
static Bool FindFramebufferAttachmentForTexture(const MG_State::GLState::FramebufferObject& framebuffer,
|
||||
const MG_State::GLState::ITextureObject& texture,
|
||||
FramebufferAttachmentType& outAttachment, Int& outLevel) {
|
||||
const auto& attachments = framebuffer.GetAllAttachmentObjects();
|
||||
for (SizeT i = 0; i < attachments.size(); ++i) {
|
||||
const auto attachmentType = static_cast<FramebufferAttachmentType>(i);
|
||||
if (attachmentType == FramebufferAttachmentType::None) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& attachment = attachments[i];
|
||||
if (!attachment.IsTexture()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto attachedTexture = attachment.GetTexture();
|
||||
if (attachedTexture && attachedTexture.get() == &texture) {
|
||||
outAttachment = attachmentType;
|
||||
outLevel = attachment.GetTextureLevel();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static Bool IsValidSampledImageLayout(VkImageLayout layout) {
|
||||
switch (layout) {
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
case VK_IMAGE_LAYOUT_GENERAL:
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
|
||||
case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
VkDeviceSize UniformDescriptorBinder::AlignUp(VkDeviceSize value, VkDeviceSize alignment) {
|
||||
if (alignment == 0) {
|
||||
return value;
|
||||
@@ -138,8 +177,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool UniformDescriptorBinder::Initialize(VkDevice device, VmaAllocator allocator,
|
||||
VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount,
|
||||
Uint32 maxBindings, Uint32 setsPerFrame, VkDeviceSize perFrameUploadBytes,
|
||||
VkTextureSamplerManager* textureSamplerManager,
|
||||
VkFramebufferManager* framebufferManager) {
|
||||
VkTextureManager* textureManager, VkSamplerManager* samplerManager) {
|
||||
Shutdown();
|
||||
|
||||
MOBILEGL_ASSERT(device != VK_NULL_HANDLE, "UniformDescriptorBinder::Initialize requires valid VkDevice");
|
||||
@@ -147,6 +185,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
MOBILEGL_ASSERT(frameCount > 0, "UniformDescriptorBinder::Initialize requires frameCount > 0");
|
||||
MOBILEGL_ASSERT(maxBindings > 0, "UniformDescriptorBinder::Initialize requires maxBindings > 0");
|
||||
MOBILEGL_ASSERT(setsPerFrame > 0, "UniformDescriptorBinder::Initialize requires setsPerFrame > 0");
|
||||
MOBILEGL_ASSERT(textureManager != nullptr,
|
||||
"UniformDescriptorBinder::Initialize requires valid texture manager");
|
||||
MOBILEGL_ASSERT(samplerManager != nullptr,
|
||||
"UniformDescriptorBinder::Initialize requires valid sampler manager");
|
||||
|
||||
m_device = device;
|
||||
m_allocator = allocator;
|
||||
@@ -156,8 +198,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_maxBindings = maxBindings;
|
||||
m_setsPerFrame = setsPerFrame;
|
||||
m_peakDescriptorSetsObserved = 0;
|
||||
m_textureSamplerManager = textureSamplerManager;
|
||||
m_framebufferManager = framebufferManager;
|
||||
m_textureManager = textureManager;
|
||||
m_samplerManager = samplerManager;
|
||||
|
||||
m_frames.resize(m_frameCount);
|
||||
for (Uint32 frameIndex = 0; frameIndex < m_frameCount; ++frameIndex) {
|
||||
@@ -219,8 +261,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_maxBindings = 0;
|
||||
m_setsPerFrame = 0;
|
||||
m_peakDescriptorSetsObserved = 0;
|
||||
m_textureSamplerManager = nullptr;
|
||||
m_framebufferManager = nullptr;
|
||||
m_textureManager = nullptr;
|
||||
m_samplerManager = nullptr;
|
||||
}
|
||||
|
||||
void UniformDescriptorBinder::BeginFrame(Uint32 frameIndex) {
|
||||
@@ -443,7 +485,86 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramLayout& layout, Uint32 binding,
|
||||
VkDescriptorImageInfo& outImageInfo) const {
|
||||
if (!m_textureSamplerManager || !MG_State::pGLContext || binding >= layout.samplerUniformLocationByBinding.size()) {
|
||||
(void)commandBuffer;
|
||||
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptor: texture manager is null");
|
||||
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptor: sampler manager is null");
|
||||
SharedPtr<MG_State::GLState::ITextureObject> texture;
|
||||
if (!ResolveSamplerTexture(program, layout, binding, texture)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Int location = layout.samplerUniformLocationByBinding[binding];
|
||||
const Int unit = program.GetUniformSamplerOrImageUnitIndex(static_cast<Uint>(location));
|
||||
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
|
||||
const auto samplerOverride = textureUnit.GetSamplerObject();
|
||||
if (!texture) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const MG_State::GLState::SamplerObject* samplerToUse = samplerOverride ? samplerOverride.get() : texture->GetSamplerObject().get();
|
||||
if (!samplerToUse) {
|
||||
return false;
|
||||
}
|
||||
VkTextureManager::TextureResource* resource =
|
||||
m_textureManager->SyncTextureAndGetDescriptor(*texture);
|
||||
if (resource == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (!IsValidSampledImageLayout(resource->layout)) {
|
||||
auto drawFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||
FramebufferAttachmentType attachmentType = FramebufferAttachmentType::None;
|
||||
Int attachmentLevel = 0;
|
||||
if (drawFbo &&
|
||||
FindFramebufferAttachmentForTexture(*drawFbo, *texture, attachmentType, attachmentLevel)) {
|
||||
MOBILEGL_ASSERT(false,
|
||||
"ResolveSamplerDescriptor: framebuffer feedback loop detected: textureId=%d is bound "
|
||||
"for sampling at binding=%u, but is also attached to drawFbo=%u as %s (level=%d, "
|
||||
"trackedLayout=%d)",
|
||||
texture->GetExternalIndex(), binding, drawFbo->GetExternalIndex(),
|
||||
MG_Util::ConvertFramebufferAttachmentTypeToString(attachmentType).c_str(),
|
||||
attachmentLevel, static_cast<Int>(resource->layout));
|
||||
}
|
||||
|
||||
MOBILEGL_ASSERT(false,
|
||||
"ResolveSamplerDescriptor: invalid sampled image layout=%d for textureId=%d, binding=%u",
|
||||
static_cast<Int>(resource->layout), texture->GetExternalIndex(), binding);
|
||||
return false;
|
||||
}
|
||||
outImageInfo = {
|
||||
.sampler = m_samplerManager->GetOrCreateSampler(*samplerToUse),
|
||||
.imageView = resource->view,
|
||||
.imageLayout = resource->layout,
|
||||
};
|
||||
return outImageInfo.sampler != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
Bool UniformDescriptorBinder::ResolveSamplerDescriptorOverride(
|
||||
const SamplerBindingOverride& samplerBindingOverride,
|
||||
VkDescriptorImageInfo& outImageInfo) const {
|
||||
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptorOverride: texture manager is null");
|
||||
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptorOverride: sampler manager is null");
|
||||
if (samplerBindingOverride.texture == nullptr || samplerBindingOverride.sampler == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* resource = m_textureManager->SyncTextureAndGetDescriptor(*samplerBindingOverride.texture);
|
||||
if (resource == nullptr || !IsValidSampledImageLayout(resource->layout)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outImageInfo = {
|
||||
.sampler = m_samplerManager->GetOrCreateSampler(*samplerBindingOverride.sampler),
|
||||
.imageView = resource->view,
|
||||
.imageLayout = resource->layout,
|
||||
};
|
||||
return outImageInfo.sampler != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
Bool UniformDescriptorBinder::ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramLayout& layout, Uint32 binding,
|
||||
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) const {
|
||||
outTexture.reset();
|
||||
if (!MG_State::pGLContext || binding >= layout.samplerUniformLocationByBinding.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -458,40 +579,35 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
|
||||
const auto samplerOverride = textureUnit.GetSamplerObject();
|
||||
|
||||
const TextureTarget preferredTarget = layout.samplerTextureTargetByBinding[binding];
|
||||
auto texture = textureUnit.GetBindingSlot(preferredTarget).GetBoundObject();
|
||||
if (!texture) {
|
||||
auto& slots = textureUnit.GetAllBindingSlots();
|
||||
for (auto& slot : slots) {
|
||||
texture = slot.GetBoundObject();
|
||||
if (texture) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!texture) {
|
||||
outTexture = textureUnit.GetBindingSlot(preferredTarget).GetBoundObject();
|
||||
return outTexture != nullptr;
|
||||
}
|
||||
|
||||
Bool UniformDescriptorBinder::CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
|
||||
Vector<MG_State::GLState::ITextureObject*>& outTextures) {
|
||||
outTextures.clear();
|
||||
ProgramLayout* layout = GetOrCreateProgramLayout(program);
|
||||
if (layout == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_framebufferManager &&
|
||||
m_framebufferManager->TransitionOffscreenColorTextureToShaderRead(commandBuffer, texture->GetExternalIndex())) {
|
||||
VkImageView offscreenView = VK_NULL_HANDLE;
|
||||
if (m_framebufferManager->GetOffscreenColorViewByTexture(texture->GetExternalIndex(), offscreenView) &&
|
||||
offscreenView != VK_NULL_HANDLE) {
|
||||
VkDescriptorImageInfo sampledInfo{};
|
||||
if (!m_textureSamplerManager->SyncTextureAndGetDescriptor(*texture, samplerOverride.get(), sampledInfo)) {
|
||||
return false;
|
||||
}
|
||||
sampledInfo.imageView = offscreenView;
|
||||
sampledInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
outImageInfo = sampledInfo;
|
||||
return true;
|
||||
for (Uint32 binding = 0; binding < m_maxBindings; ++binding) {
|
||||
if (layout->bindingKinds[binding] != BindingKind::CombinedImageSampler) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SharedPtr<MG_State::GLState::ITextureObject> texture;
|
||||
if (!ResolveSamplerTexture(program, *layout, binding, texture) || !texture) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto found = std::find(outTextures.begin(), outTextures.end(), texture.get());
|
||||
if (found == outTextures.end()) {
|
||||
outTextures.push_back(texture.get());
|
||||
}
|
||||
}
|
||||
|
||||
return m_textureSamplerManager->SyncTextureAndGetDescriptor(*texture, samplerOverride.get(), outImageInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
UniformDescriptorBinder::ProgramLayout* UniformDescriptorBinder::GetOrCreateProgramLayout(
|
||||
@@ -578,10 +694,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
outData.assign(m_maxBindings, nullptr);
|
||||
outSizes.assign(m_maxBindings, 0);
|
||||
|
||||
if (MG_State::pGLContext == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Uint32 activeUniformBlockCount = static_cast<Uint32>(program.GetActiveUniformBlocksCount());
|
||||
const Uint32 uniformBindingPointCount =
|
||||
static_cast<Uint32>(MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::Uniform));
|
||||
@@ -693,27 +805,19 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool UniformDescriptorBinder::BindProgramUniformBuffers(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout,
|
||||
Bool UniformDescriptorBinder::BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
||||
const MG_State::GLState::ProgramObject& program,
|
||||
Uint32 frameIndex) {
|
||||
if (m_frames.empty()) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: binder is not initialized");
|
||||
return false;
|
||||
}
|
||||
if (frameIndex >= m_frames.size()) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: invalid frame index %u", frameIndex);
|
||||
return false;
|
||||
}
|
||||
return BindProgramUniformBuffers(commandBuffer, program, frameIndex, nullptr);
|
||||
}
|
||||
|
||||
Bool UniformDescriptorBinder::BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
||||
const MG_State::GLState::ProgramObject& program,
|
||||
Uint32 frameIndex,
|
||||
const SamplerBindingOverride* samplerBindingOverride) {
|
||||
ProgramLayout* layout = GetOrCreateProgramLayout(program);
|
||||
if (!layout || layout->pipelineLayout == VK_NULL_HANDLE || layout->descriptorSetLayout == VK_NULL_HANDLE) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: cannot get program layout");
|
||||
return false;
|
||||
}
|
||||
if (layout->pipelineLayout != pipelineLayout) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: pipelineLayout mismatch");
|
||||
return false;
|
||||
}
|
||||
MOBILEGL_ASSERT(layout != nullptr,
|
||||
"UniformDescriptorBinder::BindProgramUniformBuffers: program layout is null");
|
||||
|
||||
auto& frame = m_frames[frameIndex];
|
||||
if (frame.descriptorPools.empty()) {
|
||||
@@ -764,8 +868,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
static const Uint8 kFallbackData[16] = {};
|
||||
VkDescriptorImageInfo fallbackImageInfo{};
|
||||
const Bool hasFallbackImage = m_textureSamplerManager && m_textureSamplerManager->GetFallbackDescriptor(fallbackImageInfo);
|
||||
MOBILEGL_ASSERT(m_textureManager != nullptr, "BindProgramUniformBuffers: texture manager is null");
|
||||
MOBILEGL_ASSERT(m_samplerManager != nullptr, "BindProgramUniformBuffers: sampler manager is null");
|
||||
|
||||
Vector<VkWriteDescriptorSet> writes;
|
||||
writes.reserve(m_maxBindings);
|
||||
@@ -830,16 +934,23 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
dynamicOffsets.push_back(static_cast<Uint32>(payloadOffset));
|
||||
} else {
|
||||
VkDescriptorImageInfo imageInfo{};
|
||||
Bool hasImage = ResolveSamplerDescriptor(commandBuffer, program, *layout, binding, imageInfo);
|
||||
Bool hasImage = false;
|
||||
if (samplerBindingOverride != nullptr &&
|
||||
samplerBindingOverride->binding == binding &&
|
||||
samplerBindingOverride->texture != nullptr &&
|
||||
samplerBindingOverride->sampler != nullptr) {
|
||||
hasImage = ResolveSamplerDescriptorOverride(*samplerBindingOverride, imageInfo);
|
||||
} else {
|
||||
hasImage = ResolveSamplerDescriptor(commandBuffer, program, *layout, binding, imageInfo);
|
||||
}
|
||||
if (!hasImage) {
|
||||
if (!hasFallbackImage) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: fallback sampler/texture is unavailable");
|
||||
return false;
|
||||
}
|
||||
imageInfo = fallbackImageInfo;
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: sampler binding %u has no valid texture descriptor",
|
||||
binding);
|
||||
return false;
|
||||
}
|
||||
if (imageInfo.sampler == VK_NULL_HANDLE || imageInfo.imageView == VK_NULL_HANDLE) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: fallback sampler/texture is unavailable");
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: sampler binding %u has null sampler or imageView",
|
||||
binding);
|
||||
return false;
|
||||
}
|
||||
imageInfos.push_back(imageInfo);
|
||||
@@ -853,7 +964,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
vkUpdateDescriptorSets(m_device, static_cast<Uint32>(writes.size()), writes.data(), 0, nullptr);
|
||||
}
|
||||
|
||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet,
|
||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, layout->pipelineLayout, 0, 1, &descriptorSet,
|
||||
static_cast<Uint32>(dynamicOffsets.size()), dynamicOffsets.data());
|
||||
return true;
|
||||
}
|
||||
@@ -872,4 +983,3 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_programLayouts.clear();
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
|
||||
@@ -9,18 +9,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "VkBufferObject.h"
|
||||
#include "VkTextureSamplerManager.h"
|
||||
#include "VkSamplerManager.h"
|
||||
#include "VkTextureManager.h"
|
||||
#include "../VkIncludes.h"
|
||||
#include <Includes.h>
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
class ITextureObject;
|
||||
class ProgramObject;
|
||||
class SamplerObject;
|
||||
}
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
class VkFramebufferManager;
|
||||
|
||||
class UniformDescriptorBinder {
|
||||
public:
|
||||
enum class BindingKind : Uint8 {
|
||||
@@ -29,17 +30,27 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
CombinedImageSampler
|
||||
};
|
||||
|
||||
struct SamplerBindingOverride {
|
||||
Uint32 binding = 0;
|
||||
MG_State::GLState::ITextureObject* texture = nullptr;
|
||||
const MG_State::GLState::SamplerObject* sampler = nullptr;
|
||||
};
|
||||
|
||||
Bool Initialize(VkDevice device, VmaAllocator allocator, VkDeviceSize minUniformBufferOffsetAlignment,
|
||||
Uint32 frameCount, Uint32 maxBindings = 16, Uint32 setsPerFrame = 64,
|
||||
VkDeviceSize perFrameUploadBytes = 4 * 1024 * 1024,
|
||||
VkTextureSamplerManager* textureSamplerManager = nullptr,
|
||||
VkFramebufferManager* framebufferManager = nullptr);
|
||||
VkTextureManager* textureManager = nullptr, VkSamplerManager* samplerManager = nullptr);
|
||||
void Shutdown();
|
||||
|
||||
void BeginFrame(Uint32 frameIndex);
|
||||
VkPipelineLayout GetOrCreatePipelineLayout(const MG_State::GLState::ProgramObject& program);
|
||||
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout,
|
||||
Bool CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
|
||||
Vector<MG_State::GLState::ITextureObject*>& outTextures);
|
||||
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
||||
const MG_State::GLState::ProgramObject& program, Uint32 frameIndex);
|
||||
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
||||
const MG_State::GLState::ProgramObject& program, Uint32 frameIndex,
|
||||
const SamplerBindingOverride* samplerBindingOverride);
|
||||
|
||||
private:
|
||||
struct DescriptorPoolBucket {
|
||||
@@ -74,9 +85,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
static TextureTarget UniformTypeToTextureTarget(GLenum glType);
|
||||
Bool ReflectSamplerBindings(const MG_State::GLState::ProgramObject& program, ProgramLayout& layout) const;
|
||||
Bool ReflectGlobalUboBinding(const MG_State::GLState::ProgramObject& program, ProgramLayout& layout) const;
|
||||
Bool ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program, const ProgramLayout& layout,
|
||||
Uint32 binding, SharedPtr<MG_State::GLState::ITextureObject>& outTexture) const;
|
||||
Bool ResolveSamplerDescriptor(VkCommandBuffer commandBuffer, const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramLayout& layout, Uint32 binding,
|
||||
VkDescriptorImageInfo& outImageInfo) const;
|
||||
Bool ResolveSamplerDescriptorOverride(const SamplerBindingOverride& samplerBindingOverride,
|
||||
VkDescriptorImageInfo& outImageInfo) const;
|
||||
Bool ReflectBindingKinds(const MG_State::GLState::ProgramObject& program, Vector<BindingKind>& outKinds) const;
|
||||
ProgramLayout* GetOrCreateProgramLayout(const MG_State::GLState::ProgramObject& program);
|
||||
Bool AllocateUploadRegion(FrameResources& frame, VkDeviceSize size, VkDeviceSize& outOffset);
|
||||
@@ -97,8 +112,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Uint32 m_maxBindings = 0;
|
||||
Uint32 m_setsPerFrame = 0;
|
||||
Uint32 m_peakDescriptorSetsObserved = 0;
|
||||
VkTextureSamplerManager* m_textureSamplerManager = nullptr;
|
||||
VkFramebufferManager* m_framebufferManager = nullptr;
|
||||
VkTextureManager* m_textureManager = nullptr;
|
||||
VkSamplerManager* m_samplerManager = nullptr;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "VkClearManager.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool VkClearManager::Initialize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void VkClearManager::Shutdown() {
|
||||
|
||||
}
|
||||
|
||||
void VkClearManager::QueueClear(GLbitfield mask, const ClearFramebufferPayload& clearPayload,
|
||||
const MG_State::GLState::FramebufferObject& drawFbo) {
|
||||
if (mask & GL_COLOR_BUFFER_BIT) {
|
||||
auto& drawbufs = drawFbo.GetDrawBuffers();
|
||||
// This should automatically work on default & offscreen FBO
|
||||
for (auto drawbuf: drawbufs) {
|
||||
if (drawbuf == FramebufferAttachmentType::None ||
|
||||
drawFbo.GetAttachment(drawbuf).IsRenderbuffer())
|
||||
continue;
|
||||
|
||||
QueueClear({
|
||||
.color = clearPayload.color,
|
||||
.attachmentType = drawbuf
|
||||
}, drawFbo.GetAttachment(drawbuf).GetTexture());
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & GL_DEPTH_BUFFER_BIT &&
|
||||
!drawFbo.GetAttachment(FramebufferAttachmentType::Depth).IsRenderbuffer()) {
|
||||
QueueClear({
|
||||
.depth = clearPayload.depth,
|
||||
.attachmentType = FramebufferAttachmentType::Depth,
|
||||
}, drawFbo.GetAttachment(FramebufferAttachmentType::Depth).GetTexture());
|
||||
}
|
||||
|
||||
if (mask & GL_STENCIL_BUFFER_BIT &&
|
||||
!drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).IsRenderbuffer()) {
|
||||
QueueClear({
|
||||
.stencil = clearPayload.stencil,
|
||||
.attachmentType = FramebufferAttachmentType::Stencil,
|
||||
}, drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).GetTexture());
|
||||
}
|
||||
}
|
||||
|
||||
void VkClearManager::QueueClear(const ClearAttachmentPayload& clearPayload,
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& texture) {
|
||||
WeakPtr<MG_State::GLState::ITextureObject> weakTexturePtr = texture;
|
||||
if (weakTexturePtr.expired())
|
||||
return;
|
||||
auto* pTexture = weakTexturePtr.lock().get();
|
||||
m_aliveObjects[pTexture] = weakTexturePtr;
|
||||
m_pendingClears[pTexture] = clearPayload;
|
||||
}
|
||||
|
||||
Bool VkClearManager::HasPendingClear(MG_State::GLState::ITextureObject* texture) {
|
||||
return m_pendingClears.find(texture) != m_pendingClears.end();
|
||||
}
|
||||
|
||||
Bool VkClearManager::GetPendingClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload) {
|
||||
if (m_aliveObjects.find(texture) == m_aliveObjects.end() ||
|
||||
m_pendingClears.find(texture) == m_pendingClears.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outPayload = m_pendingClears[texture];
|
||||
return true;
|
||||
}
|
||||
|
||||
void VkClearManager::PopPendingClear(MG_State::GLState::ITextureObject* texture) {
|
||||
m_aliveObjects.erase(texture);
|
||||
m_pendingClears.erase(texture);
|
||||
}
|
||||
|
||||
SizeT VkClearManager::CollectGarbage() {
|
||||
m_gcCounter++;
|
||||
if (m_gcCounter != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SizeT count = 0;
|
||||
for (const auto& [raw, weak]: m_aliveObjects) {
|
||||
if (weak.expired()) {
|
||||
count++;
|
||||
m_pendingClears.erase(raw);
|
||||
m_aliveObjects.erase(raw);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -0,0 +1,52 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkClearManager.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../VkIncludes.h"
|
||||
#include "../VulkanRendererConfig.h"
|
||||
#include "MG_State/GLState/FramebufferState/FramebufferObject.h"
|
||||
#include "MG_Util/Math/VectorTypes.h"
|
||||
|
||||
#include <Includes.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
struct ClearFramebufferPayload {
|
||||
FloatVec4 color;
|
||||
Float depth{};
|
||||
Uint32 stencil{};
|
||||
};
|
||||
|
||||
struct ClearAttachmentPayload {
|
||||
union {
|
||||
FloatVec4 color;
|
||||
Float depth{};
|
||||
Uint32 stencil;
|
||||
};
|
||||
FramebufferAttachmentType attachmentType = FramebufferAttachmentType::Color0;
|
||||
};
|
||||
|
||||
class VkClearManager {
|
||||
public:
|
||||
Bool Initialize();
|
||||
void Shutdown();
|
||||
|
||||
void QueueClear(GLbitfield mask, const ClearFramebufferPayload& clearPayload, const MG_State::GLState::FramebufferObject& drawFbo);
|
||||
void QueueClear(
|
||||
const ClearAttachmentPayload& clearPayload,
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& texture);
|
||||
Bool HasPendingClear(MG_State::GLState::ITextureObject* texture);
|
||||
Bool GetPendingClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload);
|
||||
void PopPendingClear(MG_State::GLState::ITextureObject* texture);
|
||||
SizeT CollectGarbage();
|
||||
private:
|
||||
Uint8 m_gcCounter = 0;
|
||||
UnorderedMap<MG_State::GLState::ITextureObject*, ClearAttachmentPayload> m_pendingClears;
|
||||
UnorderedMap<MG_State::GLState::ITextureObject*, WeakPtr<MG_State::GLState::ITextureObject>> m_aliveObjects;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -1,547 +0,0 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "VkFramebufferManager.h"
|
||||
|
||||
#include <MG_State/GLState/RenderbufferState/RenderbufferObject.h>
|
||||
#include <MG_State/GLState/TextureState/TextureEnum.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool VkFramebufferManager::Initialize(const InitInfo& initInfo) {
|
||||
m_device = initInfo.device;
|
||||
m_physicalDevice = initInfo.physicalDevice;
|
||||
return m_device != VK_NULL_HANDLE && m_physicalDevice != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void VkFramebufferManager::Shutdown() {
|
||||
for (auto& [_, target] : m_offscreenColorTargets) {
|
||||
DestroyOffscreenColorTarget(target);
|
||||
}
|
||||
m_offscreenColorTargets.clear();
|
||||
m_device = VK_NULL_HANDLE;
|
||||
m_physicalDevice = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
Bool VkFramebufferManager::EnsureOffscreenColorTarget(Uint glFboExternalIndex,
|
||||
const MG_State::GLState::FramebufferObject& glFbo) {
|
||||
const auto& colorAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Color0);
|
||||
if (!colorAttachment.IsValid() || colorAttachment.IsEmpty()) {
|
||||
MGLOG_W("VkFramebufferManager: FBO %u has no valid COLOR0 attachment", glFboExternalIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto objectVersion = glFbo.GetObjectVersion();
|
||||
auto& target = m_offscreenColorTargets[glFboExternalIndex];
|
||||
if (target.image != VK_NULL_HANDLE && target.glObjectVersion == objectVersion) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return RecreateOffscreenColorTarget(target, glFbo, colorAttachment, objectVersion);
|
||||
}
|
||||
|
||||
Bool VkFramebufferManager::TransitionOffscreenColorToAttachment(VkCommandBuffer commandBuffer,
|
||||
Uint glFboExternalIndex) {
|
||||
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||
if (it == m_offscreenColorTargets.end()) {
|
||||
MGLOG_W("VkFramebufferManager::TransitionOffscreenColorToAttachment skipped: FBO %u not found",
|
||||
glFboExternalIndex);
|
||||
return false;
|
||||
}
|
||||
auto& target = it->second;
|
||||
if (!TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target.depthStencilImage == VK_NULL_HANDLE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
if (target.depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
|
||||
target.depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
|
||||
return TransitionImageLayout(
|
||||
commandBuffer, target.depthStencilImage, target.depthStencilLayout,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, 0,
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, aspectMask);
|
||||
}
|
||||
|
||||
Bool VkFramebufferManager::TransitionOffscreenColorToTransferSrc(VkCommandBuffer commandBuffer,
|
||||
Uint glFboExternalIndex) {
|
||||
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||
if (it == m_offscreenColorTargets.end()) {
|
||||
MGLOG_W("VkFramebufferManager::TransitionOffscreenColorToTransferSrc skipped: FBO %u not found",
|
||||
glFboExternalIndex);
|
||||
return false;
|
||||
}
|
||||
auto& target = it->second;
|
||||
return TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||
VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
}
|
||||
|
||||
Bool VkFramebufferManager::TransitionOffscreenColorToTransferDst(VkCommandBuffer commandBuffer,
|
||||
Uint glFboExternalIndex) {
|
||||
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||
if (it == m_offscreenColorTargets.end()) {
|
||||
MGLOG_W("VkFramebufferManager::TransitionOffscreenColorToTransferDst skipped: FBO %u not found",
|
||||
glFboExternalIndex);
|
||||
return false;
|
||||
}
|
||||
auto& target = it->second;
|
||||
return TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
}
|
||||
|
||||
Bool VkFramebufferManager::TransitionOffscreenColorToGeneral(VkCommandBuffer commandBuffer,
|
||||
Uint glFboExternalIndex) {
|
||||
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||
if (it == m_offscreenColorTargets.end()) {
|
||||
MGLOG_W("VkFramebufferManager::TransitionOffscreenColorToGeneral skipped: FBO %u not found",
|
||||
glFboExternalIndex);
|
||||
return false;
|
||||
}
|
||||
auto& target = it->second;
|
||||
return TransitionImageLayout(commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_GENERAL,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
}
|
||||
|
||||
Bool VkFramebufferManager::TransitionOffscreenDepthStencilToTransferSrc(VkCommandBuffer commandBuffer,
|
||||
Uint glFboExternalIndex) {
|
||||
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||
if (it == m_offscreenColorTargets.end()) {
|
||||
MGLOG_W("VkFramebufferManager::TransitionOffscreenDepthStencilToTransferSrc skipped: FBO %u not found",
|
||||
glFboExternalIndex);
|
||||
return false;
|
||||
}
|
||||
auto& target = it->second;
|
||||
if (target.depthStencilImage == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
if (target.depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
|
||||
target.depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
return TransitionImageLayout(commandBuffer, target.depthStencilImage, target.depthStencilLayout,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_READ_BIT, aspectMask);
|
||||
}
|
||||
|
||||
Bool VkFramebufferManager::TransitionOffscreenDepthStencilToTransferDst(VkCommandBuffer commandBuffer,
|
||||
Uint glFboExternalIndex) {
|
||||
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||
if (it == m_offscreenColorTargets.end()) {
|
||||
MGLOG_W("VkFramebufferManager::TransitionOffscreenDepthStencilToTransferDst skipped: FBO %u not found",
|
||||
glFboExternalIndex);
|
||||
return false;
|
||||
}
|
||||
auto& target = it->second;
|
||||
if (target.depthStencilImage == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
if (target.depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
|
||||
target.depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
return TransitionImageLayout(commandBuffer, target.depthStencilImage, target.depthStencilLayout,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT, aspectMask);
|
||||
}
|
||||
|
||||
Bool VkFramebufferManager::TransitionOffscreenDepthStencilToGeneral(VkCommandBuffer commandBuffer,
|
||||
Uint glFboExternalIndex) {
|
||||
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||
if (it == m_offscreenColorTargets.end()) {
|
||||
MGLOG_W("VkFramebufferManager::TransitionOffscreenDepthStencilToGeneral skipped: FBO %u not found",
|
||||
glFboExternalIndex);
|
||||
return false;
|
||||
}
|
||||
auto& target = it->second;
|
||||
if (target.depthStencilImage == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
if (target.depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
|
||||
target.depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
return TransitionImageLayout(commandBuffer, target.depthStencilImage, target.depthStencilLayout,
|
||||
VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, aspectMask);
|
||||
}
|
||||
|
||||
Bool VkFramebufferManager::TransitionOffscreenColorTextureToShaderRead(VkCommandBuffer commandBuffer,
|
||||
Uint textureExternalIndex) {
|
||||
for (auto& [_, target] : m_offscreenColorTargets) {
|
||||
if (target.colorTextureExternalIndex != textureExternalIndex || target.image == VK_NULL_HANDLE) {
|
||||
continue;
|
||||
}
|
||||
const Bool fromUndefined = (target.layout == VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
return TransitionImageLayout(
|
||||
commandBuffer, target.image, target.layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
fromUndefined ? VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
|
||||
: (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT),
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
fromUndefined ? 0 : (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT),
|
||||
VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Bool VkFramebufferManager::GetOffscreenColorImage(Uint glFboExternalIndex, VkImage& outImage,
|
||||
VkExtent2D& outExtent) const {
|
||||
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||
if (it == m_offscreenColorTargets.end() || it->second.image == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
outImage = it->second.image;
|
||||
outExtent = it->second.extent;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkFramebufferManager::GetOffscreenDepthStencilImage(Uint glFboExternalIndex, VkImage& outImage,
|
||||
VkExtent2D& outExtent, VkFormat& outFormat) const {
|
||||
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||
if (it == m_offscreenColorTargets.end() || it->second.depthStencilImage == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
outImage = it->second.depthStencilImage;
|
||||
outExtent = it->second.extent;
|
||||
outFormat = it->second.depthStencilFormat;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkFramebufferManager::GetOffscreenColorViewByTexture(Uint textureExternalIndex,
|
||||
VkImageView& outImageView) const {
|
||||
for (const auto& [_, target] : m_offscreenColorTargets) {
|
||||
if (target.colorTextureExternalIndex != textureExternalIndex || target.imageView == VK_NULL_HANDLE) {
|
||||
continue;
|
||||
}
|
||||
outImageView = target.imageView;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Bool VkFramebufferManager::GetOffscreenRenderSurface(Uint glFboExternalIndex, VkImageView& outColorView,
|
||||
VkFormat& outColorFormat, VkImageView& outDepthStencilView,
|
||||
VkFormat& outDepthStencilFormat, VkExtent2D& outExtent) const {
|
||||
auto it = m_offscreenColorTargets.find(glFboExternalIndex);
|
||||
if (it == m_offscreenColorTargets.end() || it->second.imageView == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
outColorView = it->second.imageView;
|
||||
outColorFormat = it->second.format;
|
||||
outDepthStencilView = it->second.depthStencilImageView;
|
||||
outExtent = it->second.extent;
|
||||
outDepthStencilFormat = it->second.depthStencilFormat;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkFramebufferManager::RecreateOffscreenColorTarget(
|
||||
OffscreenColorTarget& target, const MG_State::GLState::FramebufferObject& glFbo,
|
||||
const MG_State::GLState::FramebufferAttachmentObject& colorAttachment, Uint16 glObjectVersion) {
|
||||
DestroyOffscreenColorTarget(target);
|
||||
|
||||
const auto size = colorAttachment.GetSize();
|
||||
if (size.x() <= 0 || size.y() <= 0) {
|
||||
MGLOG_W("VkFramebufferManager: COLOR0 attachment size is invalid (%d, %d)", size.x(), size.y());
|
||||
return false;
|
||||
}
|
||||
|
||||
const VkFormat format = ResolveColorFormat(colorAttachment);
|
||||
if (format == VK_FORMAT_UNDEFINED) {
|
||||
MGLOG_W("VkFramebufferManager: COLOR0 attachment format is unsupported for Vulkan clear");
|
||||
return false;
|
||||
}
|
||||
|
||||
VkImageCreateInfo imageInfo{};
|
||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.extent.width = static_cast<Uint32>(size.x());
|
||||
imageInfo.extent.height = static_cast<Uint32>(size.y());
|
||||
imageInfo.extent.depth = 1;
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.arrayLayers = 1;
|
||||
imageInfo.format = format;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VK_VERIFY(vkCreateImage(m_device, &imageInfo, nullptr, &target.image), "vkCreateImage(offscreen color)");
|
||||
|
||||
VkMemoryRequirements memoryRequirements{};
|
||||
vkGetImageMemoryRequirements(m_device, target.image, &memoryRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = memoryRequirements.size;
|
||||
allocInfo.memoryTypeIndex =
|
||||
FindMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
VK_VERIFY(vkAllocateMemory(m_device, &allocInfo, nullptr, &target.memory), "vkAllocateMemory(offscreen color)");
|
||||
VK_VERIFY(vkBindImageMemory(m_device, target.image, target.memory, 0), "vkBindImageMemory(offscreen color)");
|
||||
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = target.image;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = format;
|
||||
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.subresourceRange.baseMipLevel = 0;
|
||||
viewInfo.subresourceRange.levelCount = 1;
|
||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
viewInfo.subresourceRange.layerCount = 1;
|
||||
VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &target.imageView),
|
||||
"vkCreateImageView(offscreen color)");
|
||||
|
||||
const auto& depthAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Depth);
|
||||
const auto& stencilAttachment = glFbo.GetAttachment(FramebufferAttachmentType::Stencil);
|
||||
const Bool requestedDepthStencil = (depthAttachment.IsValid() && !depthAttachment.IsEmpty()) ||
|
||||
(stencilAttachment.IsValid() && !stencilAttachment.IsEmpty());
|
||||
VkFormat depthStencilFormat = ResolveDepthStencilFormat(depthAttachment, stencilAttachment);
|
||||
if (depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT) {
|
||||
depthStencilFormat =
|
||||
FindSupportedDepthStencilFormat({VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT});
|
||||
} else if (depthStencilFormat == VK_FORMAT_D32_SFLOAT) {
|
||||
depthStencilFormat = FindSupportedDepthStencilFormat({VK_FORMAT_D32_SFLOAT, VK_FORMAT_D16_UNORM});
|
||||
}
|
||||
const Bool hasDepthStencil = (depthStencilFormat != VK_FORMAT_UNDEFINED);
|
||||
if (requestedDepthStencil && !hasDepthStencil) {
|
||||
MGLOG_W("VkFramebufferManager: FBO %u depth/stencil attachment exists but format is unsupported",
|
||||
glFbo.GetExternalIndex());
|
||||
}
|
||||
if (hasDepthStencil) {
|
||||
VkImageCreateInfo depthImageInfo{};
|
||||
depthImageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
depthImageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
depthImageInfo.extent.width = static_cast<Uint32>(size.x());
|
||||
depthImageInfo.extent.height = static_cast<Uint32>(size.y());
|
||||
depthImageInfo.extent.depth = 1;
|
||||
depthImageInfo.mipLevels = 1;
|
||||
depthImageInfo.arrayLayers = 1;
|
||||
depthImageInfo.format = depthStencilFormat;
|
||||
depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VK_VERIFY(vkCreateImage(m_device, &depthImageInfo, nullptr, &target.depthStencilImage),
|
||||
"vkCreateImage(offscreen depth/stencil)");
|
||||
|
||||
VkMemoryRequirements depthMemoryRequirements{};
|
||||
vkGetImageMemoryRequirements(m_device, target.depthStencilImage, &depthMemoryRequirements);
|
||||
VkMemoryAllocateInfo depthAllocInfo{};
|
||||
depthAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
depthAllocInfo.allocationSize = depthMemoryRequirements.size;
|
||||
depthAllocInfo.memoryTypeIndex =
|
||||
FindMemoryType(depthMemoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
VK_VERIFY(vkAllocateMemory(m_device, &depthAllocInfo, nullptr, &target.depthStencilMemory),
|
||||
"vkAllocateMemory(offscreen depth/stencil)");
|
||||
VK_VERIFY(vkBindImageMemory(m_device, target.depthStencilImage, target.depthStencilMemory, 0),
|
||||
"vkBindImageMemory(offscreen depth/stencil)");
|
||||
|
||||
VkImageAspectFlags depthAspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
if (depthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
|
||||
depthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||
depthAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
VkImageViewCreateInfo depthViewInfo{};
|
||||
depthViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
depthViewInfo.image = target.depthStencilImage;
|
||||
depthViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
depthViewInfo.format = depthStencilFormat;
|
||||
depthViewInfo.subresourceRange.aspectMask = depthAspectMask;
|
||||
depthViewInfo.subresourceRange.baseMipLevel = 0;
|
||||
depthViewInfo.subresourceRange.levelCount = 1;
|
||||
depthViewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
depthViewInfo.subresourceRange.layerCount = 1;
|
||||
VK_VERIFY(vkCreateImageView(m_device, &depthViewInfo, nullptr, &target.depthStencilImageView),
|
||||
"vkCreateImageView(offscreen depth/stencil)");
|
||||
}
|
||||
|
||||
target.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
target.extent = {static_cast<Uint32>(size.x()), static_cast<Uint32>(size.y())};
|
||||
target.format = format;
|
||||
target.depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
target.depthStencilFormat = depthStencilFormat;
|
||||
target.glObjectVersion = glObjectVersion;
|
||||
target.colorTextureExternalIndex = (colorAttachment.IsTexture() && colorAttachment.GetTexture())
|
||||
? colorAttachment.GetTexture()->GetExternalIndex()
|
||||
: 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void VkFramebufferManager::DestroyOffscreenColorTarget(OffscreenColorTarget& target) {
|
||||
if (target.imageView != VK_NULL_HANDLE) {
|
||||
vkDestroyImageView(m_device, target.imageView, nullptr);
|
||||
target.imageView = VK_NULL_HANDLE;
|
||||
}
|
||||
if (target.depthStencilImageView != VK_NULL_HANDLE) {
|
||||
vkDestroyImageView(m_device, target.depthStencilImageView, nullptr);
|
||||
target.depthStencilImageView = VK_NULL_HANDLE;
|
||||
}
|
||||
if (target.image != VK_NULL_HANDLE) {
|
||||
vkDestroyImage(m_device, target.image, nullptr);
|
||||
target.image = VK_NULL_HANDLE;
|
||||
}
|
||||
if (target.depthStencilImage != VK_NULL_HANDLE) {
|
||||
vkDestroyImage(m_device, target.depthStencilImage, nullptr);
|
||||
target.depthStencilImage = VK_NULL_HANDLE;
|
||||
}
|
||||
if (target.memory != VK_NULL_HANDLE) {
|
||||
vkFreeMemory(m_device, target.memory, nullptr);
|
||||
target.memory = VK_NULL_HANDLE;
|
||||
}
|
||||
if (target.depthStencilMemory != VK_NULL_HANDLE) {
|
||||
vkFreeMemory(m_device, target.depthStencilMemory, nullptr);
|
||||
target.depthStencilMemory = VK_NULL_HANDLE;
|
||||
}
|
||||
target.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
target.depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
target.extent = {0, 0};
|
||||
target.format = VK_FORMAT_UNDEFINED;
|
||||
target.depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
target.glObjectVersion = 0;
|
||||
target.colorTextureExternalIndex = 0;
|
||||
}
|
||||
|
||||
Bool VkFramebufferManager::TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image,
|
||||
VkImageLayout& trackedLayout, VkImageLayout newLayout,
|
||||
VkPipelineStageFlags srcStageMask,
|
||||
VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask,
|
||||
VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask) {
|
||||
if (image == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
if (trackedLayout == newLayout) {
|
||||
return true;
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.srcAccessMask = srcAccessMask;
|
||||
barrier.dstAccessMask = dstAccessMask;
|
||||
barrier.oldLayout = trackedLayout;
|
||||
barrier.newLayout = newLayout;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = image;
|
||||
barrier.subresourceRange.aspectMask = aspectMask;
|
||||
barrier.subresourceRange.baseMipLevel = 0;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
vkCmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
|
||||
trackedLayout = newLayout;
|
||||
return true;
|
||||
}
|
||||
|
||||
Uint32 VkFramebufferManager::FindMemoryType(Uint32 typeFilter, VkMemoryPropertyFlags properties) const {
|
||||
VkPhysicalDeviceMemoryProperties memoryProperties{};
|
||||
vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &memoryProperties);
|
||||
for (Uint32 i = 0; i < memoryProperties.memoryTypeCount; ++i) {
|
||||
if ((typeFilter & (1U << i)) &&
|
||||
(memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
MOBILEGL_ASSERT(false, "VkFramebufferManager::FindMemoryType failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
VkFormat VkFramebufferManager::ResolveColorFormat(
|
||||
const MG_State::GLState::FramebufferAttachmentObject& colorAttachment) {
|
||||
TextureInternalFormat internalFormat = TextureInternalFormat::Unknown;
|
||||
if (colorAttachment.IsTexture()) {
|
||||
const auto texture = colorAttachment.GetTexture();
|
||||
internalFormat = texture ? texture->GetFormat() : TextureInternalFormat::Unknown;
|
||||
} else if (colorAttachment.IsRenderbuffer()) {
|
||||
const auto renderbuffer = colorAttachment.GetRenderbuffer();
|
||||
internalFormat = renderbuffer ? renderbuffer->GetInternalFormat() : TextureInternalFormat::Unknown;
|
||||
}
|
||||
|
||||
switch (internalFormat) {
|
||||
case TextureInternalFormat::RGBA:
|
||||
case TextureInternalFormat::RGBA8:
|
||||
case TextureInternalFormat::SRGB8Alpha8:
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
default:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
VkFormat VkFramebufferManager::ResolveDepthStencilFormat(
|
||||
const MG_State::GLState::FramebufferAttachmentObject& depthAttachment,
|
||||
const MG_State::GLState::FramebufferAttachmentObject& stencilAttachment) {
|
||||
const auto resolveAttachmentFormat = [](const MG_State::GLState::FramebufferAttachmentObject& attachment) {
|
||||
TextureInternalFormat internalFormat = TextureInternalFormat::Unknown;
|
||||
if (attachment.IsTexture()) {
|
||||
const auto texture = attachment.GetTexture();
|
||||
internalFormat = texture ? texture->GetFormat() : TextureInternalFormat::Unknown;
|
||||
} else if (attachment.IsRenderbuffer()) {
|
||||
const auto renderbuffer = attachment.GetRenderbuffer();
|
||||
internalFormat = renderbuffer ? renderbuffer->GetInternalFormat() : TextureInternalFormat::Unknown;
|
||||
}
|
||||
return internalFormat;
|
||||
};
|
||||
|
||||
const auto depthFormat = resolveAttachmentFormat(depthAttachment);
|
||||
const auto stencilFormat = resolveAttachmentFormat(stencilAttachment);
|
||||
|
||||
switch (depthFormat) {
|
||||
case TextureInternalFormat::Depth24Stencil8:
|
||||
case TextureInternalFormat::Depth32FStencil8:
|
||||
case TextureInternalFormat::DepthStencil:
|
||||
return VK_FORMAT_D24_UNORM_S8_UINT;
|
||||
case TextureInternalFormat::DepthComponent16:
|
||||
return VK_FORMAT_D16_UNORM;
|
||||
case TextureInternalFormat::DepthComponent24:
|
||||
case TextureInternalFormat::DepthComponent32:
|
||||
case TextureInternalFormat::DepthComponent32F:
|
||||
case TextureInternalFormat::DepthComponent:
|
||||
return VK_FORMAT_D32_SFLOAT;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (stencilFormat) {
|
||||
case TextureInternalFormat::Depth24Stencil8:
|
||||
case TextureInternalFormat::Depth32FStencil8:
|
||||
case TextureInternalFormat::DepthStencil:
|
||||
return VK_FORMAT_D24_UNORM_S8_UINT;
|
||||
default:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
VkFormat VkFramebufferManager::FindSupportedDepthStencilFormat(const Vector<VkFormat>& candidates) const {
|
||||
for (auto format : candidates) {
|
||||
VkFormatProperties properties{};
|
||||
vkGetPhysicalDeviceFormatProperties(m_physicalDevice, format, &properties);
|
||||
if ((properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -1,83 +0,0 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../VkIncludes.h"
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
class VkFramebufferManager {
|
||||
public:
|
||||
struct InitInfo {
|
||||
VkDevice device = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
VkFramebufferManager() = default;
|
||||
~VkFramebufferManager() = default;
|
||||
|
||||
Bool Initialize(const InitInfo& initInfo);
|
||||
void Shutdown();
|
||||
|
||||
Bool EnsureOffscreenColorTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo);
|
||||
Bool TransitionOffscreenColorToAttachment(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
||||
Bool TransitionOffscreenColorToTransferSrc(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
||||
Bool TransitionOffscreenColorToTransferDst(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
||||
Bool TransitionOffscreenColorToGeneral(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
||||
Bool TransitionOffscreenDepthStencilToTransferSrc(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
||||
Bool TransitionOffscreenDepthStencilToTransferDst(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
||||
Bool TransitionOffscreenDepthStencilToGeneral(VkCommandBuffer commandBuffer, Uint glFboExternalIndex);
|
||||
Bool TransitionOffscreenColorTextureToShaderRead(VkCommandBuffer commandBuffer, Uint textureExternalIndex);
|
||||
Bool GetOffscreenColorImage(Uint glFboExternalIndex, VkImage& outImage, VkExtent2D& outExtent) const;
|
||||
Bool GetOffscreenDepthStencilImage(Uint glFboExternalIndex, VkImage& outImage, VkExtent2D& outExtent,
|
||||
VkFormat& outFormat) const;
|
||||
Bool GetOffscreenColorViewByTexture(Uint textureExternalIndex, VkImageView& outImageView) const;
|
||||
Bool GetOffscreenRenderSurface(Uint glFboExternalIndex, VkImageView& outColorView, VkFormat& outColorFormat,
|
||||
VkImageView& outDepthStencilView, VkFormat& outDepthStencilFormat,
|
||||
VkExtent2D& outExtent) const;
|
||||
|
||||
private:
|
||||
struct OffscreenColorTarget {
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
||||
VkImageView imageView = VK_NULL_HANDLE;
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VkExtent2D extent = {0, 0};
|
||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||
VkImage depthStencilImage = VK_NULL_HANDLE;
|
||||
VkDeviceMemory depthStencilMemory = VK_NULL_HANDLE;
|
||||
VkImageView depthStencilImageView = VK_NULL_HANDLE;
|
||||
VkImageLayout depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
Uint16 glObjectVersion = 0;
|
||||
Uint colorTextureExternalIndex = 0;
|
||||
};
|
||||
|
||||
Bool RecreateOffscreenColorTarget(OffscreenColorTarget& target,
|
||||
const MG_State::GLState::FramebufferObject& glFbo,
|
||||
const MG_State::GLState::FramebufferAttachmentObject& colorAttachment,
|
||||
Uint16 glObjectVersion);
|
||||
void DestroyOffscreenColorTarget(OffscreenColorTarget& target);
|
||||
Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout,
|
||||
VkImageLayout newLayout, VkPipelineStageFlags srcStageMask,
|
||||
VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask,
|
||||
VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask);
|
||||
Uint32 FindMemoryType(Uint32 typeFilter, VkMemoryPropertyFlags properties) const;
|
||||
static VkFormat ResolveColorFormat(const MG_State::GLState::FramebufferAttachmentObject& colorAttachment);
|
||||
static VkFormat ResolveDepthStencilFormat(
|
||||
const MG_State::GLState::FramebufferAttachmentObject& depthAttachment,
|
||||
const MG_State::GLState::FramebufferAttachmentObject& stencilAttachment);
|
||||
VkFormat FindSupportedDepthStencilFormat(const Vector<VkFormat>& candidates) const;
|
||||
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
|
||||
UnorderedMap<Uint, OffscreenColorTarget> m_offscreenColorTargets;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -8,340 +8,463 @@
|
||||
|
||||
#include "VkRenderPassManager.h"
|
||||
|
||||
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
|
||||
#include "MG_State/GLState/TextureState/TextureObject2D.h"
|
||||
#include "MG_Util/Converters/MGToVk/TextureEnumConverter.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool VkRenderPassManager::Initialize(const InitInfo& initInfo) {
|
||||
Shutdown();
|
||||
VkRenderPassManager::VkRenderPassManager(VkDevice device,
|
||||
const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager,
|
||||
SwapchainObject& swapchainObject):
|
||||
m_device(device), m_config(config), m_clearManager(clearManager), m_textureManager(textureManager),
|
||||
m_swapchainObject(swapchainObject) {
|
||||
RenderPassEntry::s_device = m_device;
|
||||
s_clearManager = &m_clearManager;
|
||||
s_textureManager = &m_textureManager;
|
||||
s_swapchainObject = &m_swapchainObject;
|
||||
}
|
||||
|
||||
if (initInfo.device == VK_NULL_HANDLE || initInfo.colorFormat == VK_FORMAT_UNDEFINED ||
|
||||
initInfo.depthStencilFormat == VK_FORMAT_UNDEFINED) {
|
||||
return false;
|
||||
}
|
||||
VkRenderPassManager::~VkRenderPassManager() {}
|
||||
|
||||
m_device = initInfo.device;
|
||||
m_colorFormat = initInfo.colorFormat;
|
||||
m_depthStencilFormat = initInfo.depthStencilFormat;
|
||||
m_renderPassLoad = CreateDefaultRenderPass(VK_ATTACHMENT_LOAD_OP_LOAD);
|
||||
m_renderPassClear = CreateDefaultRenderPass(VK_ATTACHMENT_LOAD_OP_CLEAR);
|
||||
MGLOG_D("VkRenderPassManager: RenderPasses created (LOAD/CLEAR).");
|
||||
return m_renderPassLoad != VK_NULL_HANDLE && m_renderPassClear != VK_NULL_HANDLE;
|
||||
Bool VkRenderPassManager::Initialize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void VkRenderPassManager::Shutdown() {
|
||||
DestroyDefaultFramebuffers();
|
||||
for (auto& [_, target] : m_offscreenRenderTargets) {
|
||||
DestroyOffscreenRenderTarget(target);
|
||||
}
|
||||
m_offscreenRenderTargets.clear();
|
||||
}
|
||||
|
||||
if (m_device != VK_NULL_HANDLE) {
|
||||
if (m_renderPassClear != VK_NULL_HANDLE) {
|
||||
vkDestroyRenderPass(m_device, m_renderPassClear, nullptr);
|
||||
VkRenderPassManager::HashType VkRenderPassManager::ComputeHash(
|
||||
const MG_State::GLState::FramebufferObject& fbo, Uint32 swapchainImageIndex, Bool includePendingClear) const {
|
||||
XXHASH_VERIFY(XXH64_reset(m_hashState, m_config.CacheVersion));
|
||||
const Bool isDefaultFbo = (&fbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get());
|
||||
if (isDefaultFbo) {
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &swapchainImageIndex, sizeof(swapchainImageIndex)));
|
||||
}
|
||||
auto& drawBuffers = fbo.GetDrawBuffers();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, drawBuffers.data(), drawBuffers.size() * sizeof(drawBuffers[0])));
|
||||
auto readBuffer = fbo.GetReadBuffer();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &readBuffer, sizeof(FramebufferAttachmentType)));
|
||||
Int validDrawBufCount = 0;
|
||||
for (Int i = 0; i < drawBuffers.size(); ++i) {
|
||||
auto drawbuf = drawBuffers[i];
|
||||
if (drawbuf != FramebufferAttachmentType::None)
|
||||
validDrawBufCount = std::max(validDrawBufCount, i + 1);
|
||||
}
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &validDrawBufCount, sizeof(validDrawBufCount)));
|
||||
|
||||
auto combineFramebufferAttachmentObjHash = [&](FramebufferAttachmentType attachment) {
|
||||
auto& att = fbo.GetAttachment(attachment);
|
||||
|
||||
Int type = 0;
|
||||
if (att.IsEmpty()) type = 0;
|
||||
else if (att.IsTexture()) type = 1;
|
||||
else if (att.IsRenderbuffer()) type = 2;
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &type, sizeof(type)));
|
||||
void* contentPtr = nullptr;
|
||||
if (att.IsTexture())
|
||||
contentPtr = att.GetTexture().get();
|
||||
else if (att.IsRenderbuffer())
|
||||
contentPtr = att.GetRenderbuffer().get();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &contentPtr, sizeof(contentPtr)));
|
||||
|
||||
if (includePendingClear && att.IsTexture()) {
|
||||
auto* texture = att.GetTexture().get();
|
||||
auto hasClear = m_clearManager.HasPendingClear(texture);
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &hasClear, sizeof(hasClear)));
|
||||
if (hasClear) {
|
||||
ClearAttachmentPayload clearPayload{};
|
||||
Bool hasPayload = m_clearManager.GetPendingClear(texture, clearPayload);
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &hasPayload, sizeof(hasPayload)));
|
||||
if (hasPayload) {
|
||||
XXHASH_VERIFY(XXH64_update(
|
||||
m_hashState, &clearPayload.attachmentType, sizeof(clearPayload.attachmentType)));
|
||||
}
|
||||
}
|
||||
|
||||
VkImageLayout currentLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
if (isDefaultFbo) {
|
||||
if (attachment >= FramebufferAttachmentType::Color0 &&
|
||||
attachment <= FramebufferAttachmentType::Color31) {
|
||||
currentLayout = m_swapchainObject.GetImageLayout(swapchainImageIndex);
|
||||
} else if (attachment == FramebufferAttachmentType::Depth ||
|
||||
attachment == FramebufferAttachmentType::Stencil) {
|
||||
currentLayout = m_swapchainObject.GetDepthStencilImageLayout(swapchainImageIndex);
|
||||
}
|
||||
} else {
|
||||
auto* resource = m_textureManager.SyncTextureAndGetDescriptor(*texture);
|
||||
if (resource != nullptr) {
|
||||
currentLayout = resource->layout;
|
||||
}
|
||||
}
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, ¤tLayout, sizeof(currentLayout)));
|
||||
}
|
||||
if (m_renderPassLoad != VK_NULL_HANDLE) {
|
||||
vkDestroyRenderPass(m_device, m_renderPassLoad, nullptr);
|
||||
};
|
||||
|
||||
for (Int i = 0; i < validDrawBufCount; ++i) {
|
||||
auto drawbuf = drawBuffers[i];
|
||||
combineFramebufferAttachmentObjHash(drawbuf);
|
||||
}
|
||||
|
||||
combineFramebufferAttachmentObjHash(FramebufferAttachmentType::Depth);
|
||||
combineFramebufferAttachmentObjHash(FramebufferAttachmentType::Stencil);
|
||||
|
||||
return XXH64_digest(m_hashState);
|
||||
}
|
||||
|
||||
RenderPassEntry& VkRenderPassManager::GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo,
|
||||
Uint32 swapchainImageIndex) {
|
||||
// retrieve from cache first
|
||||
auto* activeRenderPass = GetActiveRenderPass();
|
||||
auto compatibilityHash = ComputeHash(fbo, swapchainImageIndex, false);
|
||||
if (activeRenderPass != nullptr && activeRenderPass->CompatibleWith(compatibilityHash)) {
|
||||
auto activeIt = m_renderPasses.find(activeRenderPass->hash);
|
||||
MOBILEGL_ASSERT(activeIt != m_renderPasses.end(),
|
||||
"GetOrCreateRenderPass: active render pass hash=0x%llx is missing from cache",
|
||||
static_cast<unsigned long long>(activeRenderPass->hash));
|
||||
return activeIt->second;
|
||||
}
|
||||
auto hash = ComputeHash(fbo, swapchainImageIndex, true);
|
||||
auto it = m_renderPasses.find(hash);
|
||||
if (it != m_renderPasses.end())
|
||||
return it->second;
|
||||
|
||||
Bool isDefaultFbo = (&fbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get());
|
||||
// Color attachment
|
||||
auto& drawbufs = fbo.GetDrawBuffers();
|
||||
Int validDrawBufCount = 0;
|
||||
for (Int i = 0; i < drawbufs.size(); ++i) {
|
||||
auto drawbuf = drawbufs[i];
|
||||
if (drawbuf != FramebufferAttachmentType::None)
|
||||
validDrawBufCount = std::max(validDrawBufCount, i + 1);
|
||||
}
|
||||
|
||||
Int width = 0;
|
||||
Int height = 0;
|
||||
Vector<VkAttachmentDescription> attachmentDescriptions(validDrawBufCount);
|
||||
Vector<VkAttachmentReference> colorAttachmentRefs(validDrawBufCount);
|
||||
Vector<PendingClearAttachmentInfo> pendingClearAttachments;
|
||||
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
|
||||
auto& textureResources = RenderPassEntry::s_textureResourcesScratch;
|
||||
textureResources.clear();
|
||||
textureResources.resize(validDrawBufCount, nullptr);
|
||||
Vector<VkImageView> attachmentViews(validDrawBufCount, VK_NULL_HANDLE);
|
||||
// This should automatically work on default & offscreen FBO
|
||||
// assuming default FBO has the right param
|
||||
for (Int i = 0; i < validDrawBufCount; ++i) {
|
||||
auto drawbuf = drawbufs[i];
|
||||
if (drawbuf == FramebufferAttachmentType::None ||
|
||||
fbo.GetAttachment(drawbuf).IsRenderbuffer())
|
||||
continue;
|
||||
|
||||
auto& att = fbo.GetAttachment(drawbuf);
|
||||
auto* texture = att.GetTexture().get();
|
||||
const auto textureTarget = texture->GetTarget();
|
||||
|
||||
// Color attachment description
|
||||
VkAttachmentDescription& desc = attachmentDescriptions[i];
|
||||
switch (textureTarget) {
|
||||
case TextureTarget::Texture2D: {
|
||||
auto* texture2d =
|
||||
static_cast<MG_State::GLState::TextureObject2D*>(texture);
|
||||
desc.flags = 0;
|
||||
desc.format =
|
||||
MG_Util::ConvertTextureInternalFormatToVkEnum(
|
||||
texture2d->GetFormat());
|
||||
desc.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
ClearAttachmentPayload clearPayload{};
|
||||
Bool hasClear = m_clearManager.GetPendingClear(texture, clearPayload);
|
||||
VkImageLayout trackedColorLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
desc.loadOp = hasClear ?
|
||||
VK_ATTACHMENT_LOAD_OP_CLEAR :
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
desc.finalLayout = isDefaultFbo ?
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR :
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
if (hasClear) {
|
||||
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
|
||||
.attachmentIndex = static_cast<Uint32>(i),
|
||||
.texture = texture
|
||||
});
|
||||
}
|
||||
if (width == 0)
|
||||
width = texture2d->GetBaseSize().x();
|
||||
if (height == 0)
|
||||
height = texture2d->GetBaseSize().y();
|
||||
|
||||
if (isDefaultFbo) {
|
||||
const auto& swapchainViews = m_swapchainObject.GetImageViews();
|
||||
MOBILEGL_ASSERT(swapchainImageIndex < swapchainViews.size(),
|
||||
"GetOrCreateRenderPass: swapchain image index out of range");
|
||||
trackedColorLayout = m_swapchainObject.GetImageLayout(swapchainImageIndex);
|
||||
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
||||
.target = TrackedAttachmentTarget::SwapchainColor,
|
||||
.swapchainImageIndex = swapchainImageIndex,
|
||||
.finalLayout = desc.finalLayout,
|
||||
});
|
||||
attachmentViews[i] = swapchainViews[swapchainImageIndex];
|
||||
} else {
|
||||
textureResources[i] = m_textureManager.SyncTextureAndGetDescriptor(*texture);
|
||||
MOBILEGL_ASSERT(textureResources[i],
|
||||
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at color attachment %d", i);
|
||||
trackedColorLayout = textureResources[i]->layout;
|
||||
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
||||
.target = TrackedAttachmentTarget::Texture,
|
||||
.texture = texture,
|
||||
.finalLayout = desc.finalLayout,
|
||||
});
|
||||
attachmentViews[i] = textureResources[i]->view;
|
||||
}
|
||||
|
||||
if (!hasClear && trackedColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
|
||||
MGLOG_W("GetOrCreateRenderPass: color attachment textureId=%d starts with undefined layout and no clear; "
|
||||
"using LOAD_OP_DONT_CARE",
|
||||
texture->GetExternalIndex());
|
||||
desc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
}
|
||||
desc.initialLayout = (hasClear || trackedColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) ?
|
||||
VK_IMAGE_LAYOUT_UNDEFINED :
|
||||
trackedColorLayout;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOBILEGL_ASSERT(false, "Unsupported texture target");
|
||||
}
|
||||
|
||||
// Attachment reference
|
||||
VkAttachmentReference& attachmentRef = colorAttachmentRefs[i];
|
||||
attachmentRef.attachment = i;
|
||||
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
m_renderPassClear = VK_NULL_HANDLE;
|
||||
m_renderPassLoad = VK_NULL_HANDLE;
|
||||
m_colorFormat = VK_FORMAT_UNDEFINED;
|
||||
m_depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
m_defaultExtent = {0, 0};
|
||||
m_device = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
Bool VkRenderPassManager::RecreateDefaultFramebuffers(const Vector<VkImageView>& colorViews,
|
||||
const Vector<VkImageView>& depthStencilViews,
|
||||
VkExtent2D extent) {
|
||||
DestroyDefaultFramebuffers();
|
||||
|
||||
if (m_device == VK_NULL_HANDLE || m_renderPassLoad == VK_NULL_HANDLE || extent.width == 0 ||
|
||||
extent.height == 0 || colorViews.empty() || colorViews.size() != depthStencilViews.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_defaultFramebuffers.reserve(colorViews.size());
|
||||
for (SizeT i = 0; i < colorViews.size(); ++i) {
|
||||
if (colorViews[i] == VK_NULL_HANDLE || depthStencilViews[i] == VK_NULL_HANDLE) {
|
||||
DestroyDefaultFramebuffers();
|
||||
return false;
|
||||
// Depth attachment description
|
||||
auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth);
|
||||
VkAttachmentDescription depthAttachmentDescription;
|
||||
VkAttachmentReference depthAttachmentRef;
|
||||
depthAttachmentRef.attachment = VK_ATTACHMENT_UNUSED;
|
||||
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
VkTextureManager::TextureResource* depthTextureResource = nullptr;
|
||||
if (depthAtt.IsComplete() && depthAtt.IsTexture()) {
|
||||
auto& texture = *depthAtt.GetTexture();
|
||||
const Uint32 depthAttachmentIndex = static_cast<Uint32>(attachmentDescriptions.size());
|
||||
ClearAttachmentPayload clearPayload{};
|
||||
Bool hasClear = m_clearManager.GetPendingClear(&texture, clearPayload);
|
||||
Bool clearDepth = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Depth;
|
||||
Bool clearStencil = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Stencil;
|
||||
VkImageLayout trackedDepthLayout = isDefaultFbo ?
|
||||
m_swapchainObject.GetDepthStencilImageLayout(swapchainImageIndex) :
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
if (!isDefaultFbo) {
|
||||
depthTextureResource = m_textureManager.SyncTextureAndGetDescriptor(texture);
|
||||
MOBILEGL_ASSERT(depthTextureResource,
|
||||
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at depth attachment");
|
||||
trackedDepthLayout = depthTextureResource->layout;
|
||||
}
|
||||
VkImageView attachments[] = {colorViews[i], depthStencilViews[i]};
|
||||
VkFramebufferCreateInfo createInfo{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
|
||||
createInfo.renderPass = m_renderPassLoad;
|
||||
createInfo.attachmentCount = static_cast<Uint32>(std::size(attachments));
|
||||
createInfo.pAttachments = attachments;
|
||||
createInfo.width = extent.width;
|
||||
createInfo.height = extent.height;
|
||||
createInfo.layers = 1;
|
||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||
if (vkCreateFramebuffer(m_device, &createInfo, nullptr, &framebuffer) != VK_SUCCESS) {
|
||||
DestroyDefaultFramebuffers();
|
||||
return false;
|
||||
depthAttachmentDescription.flags = 0;
|
||||
depthAttachmentDescription.format =
|
||||
MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat());
|
||||
depthAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
depthAttachmentDescription.loadOp = clearDepth ?
|
||||
VK_ATTACHMENT_LOAD_OP_CLEAR :
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
depthAttachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
depthAttachmentDescription.stencilLoadOp = clearStencil ?
|
||||
VK_ATTACHMENT_LOAD_OP_CLEAR :
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
depthAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
if (trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
|
||||
if (!clearDepth) {
|
||||
depthAttachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
}
|
||||
if (!clearStencil) {
|
||||
depthAttachmentDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
}
|
||||
}
|
||||
m_defaultFramebuffers.push_back(framebuffer);
|
||||
}
|
||||
m_defaultExtent = extent;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkRenderPassManager::GetDefaultRenderTarget(Uint32 imageIndex, VkRenderPass& outRenderPass,
|
||||
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent,
|
||||
VkFormat& outDepthStencilFormat) const {
|
||||
if (imageIndex >= m_defaultFramebuffers.size() || m_renderPassLoad == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
outRenderPass = m_renderPassLoad;
|
||||
outFramebuffer = m_defaultFramebuffers[imageIndex];
|
||||
outExtent = m_defaultExtent;
|
||||
outDepthStencilFormat = m_depthStencilFormat;
|
||||
return outFramebuffer != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
Bool VkRenderPassManager::EnsureOffscreenRenderTarget(const OffscreenRenderTargetInfo& targetInfo) {
|
||||
if (m_device == VK_NULL_HANDLE || targetInfo.colorView == VK_NULL_HANDLE ||
|
||||
targetInfo.colorFormat == VK_FORMAT_UNDEFINED || targetInfo.extent.width == 0 ||
|
||||
targetInfo.extent.height == 0) {
|
||||
return false;
|
||||
depthAttachmentDescription.initialLayout =
|
||||
(clearDepth && clearStencil) || trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED ?
|
||||
VK_IMAGE_LAYOUT_UNDEFINED :
|
||||
trackedDepthLayout;
|
||||
if (hasClear) {
|
||||
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
|
||||
.attachmentIndex = depthAttachmentIndex,
|
||||
.texture = &texture
|
||||
});
|
||||
}
|
||||
if (isDefaultFbo) {
|
||||
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
||||
.target = TrackedAttachmentTarget::SwapchainDepthStencil,
|
||||
.swapchainImageIndex = swapchainImageIndex,
|
||||
.finalLayout = depthAttachmentDescription.finalLayout,
|
||||
});
|
||||
attachmentViews.emplace_back(m_swapchainObject.GetDepthStencilImageView(swapchainImageIndex));
|
||||
} else {
|
||||
MOBILEGL_ASSERT(clearDepth || clearStencil || depthTextureResource->layout != VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
"GetOrCreateRenderPass: depth attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD",
|
||||
texture.GetExternalIndex());
|
||||
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
||||
.target = TrackedAttachmentTarget::Texture,
|
||||
.texture = &texture,
|
||||
.finalLayout = depthAttachmentDescription.finalLayout,
|
||||
});
|
||||
textureResources.emplace_back(depthTextureResource);
|
||||
attachmentViews.emplace_back(depthTextureResource->view);
|
||||
if (width == 0 || height == 0) {
|
||||
auto texture2d = static_cast<MG_State::GLState::TextureObject2D*>(&texture);
|
||||
width = texture2d->GetBaseSize().x();
|
||||
height = texture2d->GetBaseSize().y();
|
||||
}
|
||||
}
|
||||
attachmentDescriptions.emplace_back(depthAttachmentDescription);
|
||||
depthAttachmentRef.attachment = depthAttachmentIndex;
|
||||
}
|
||||
|
||||
const Bool hasDepthStencil =
|
||||
targetInfo.depthStencilView != VK_NULL_HANDLE && targetInfo.depthStencilFormat != VK_FORMAT_UNDEFINED;
|
||||
// Subpass
|
||||
VkSubpassDescription subpassDesc;
|
||||
subpassDesc.flags = 0;
|
||||
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpassDesc.inputAttachmentCount = 0;
|
||||
subpassDesc.pInputAttachments = nullptr;
|
||||
subpassDesc.colorAttachmentCount = colorAttachmentRefs.size();
|
||||
subpassDesc.pColorAttachments = colorAttachmentRefs.data();
|
||||
subpassDesc.pResolveAttachments = nullptr;
|
||||
subpassDesc.pDepthStencilAttachment = depthAtt.IsComplete() ? &depthAttachmentRef : VK_NULL_HANDLE;
|
||||
subpassDesc.preserveAttachmentCount = 0;
|
||||
subpassDesc.pPreserveAttachments = nullptr;
|
||||
|
||||
auto& target = m_offscreenRenderTargets[targetInfo.targetExternalIndex];
|
||||
if (target.framebuffer != VK_NULL_HANDLE && target.renderPassLoad != VK_NULL_HANDLE &&
|
||||
target.targetVersion == targetInfo.targetVersion && target.colorView == targetInfo.colorView &&
|
||||
target.colorFormat == targetInfo.colorFormat && target.depthStencilView == targetInfo.depthStencilView &&
|
||||
target.depthStencilFormat == targetInfo.depthStencilFormat &&
|
||||
target.extent.width == targetInfo.extent.width && target.extent.height == targetInfo.extent.height) {
|
||||
return true;
|
||||
}
|
||||
|
||||
DestroyOffscreenRenderTarget(target);
|
||||
|
||||
const VkFormat depthStencilFormat = hasDepthStencil ? targetInfo.depthStencilFormat : VK_FORMAT_UNDEFINED;
|
||||
target.renderPassLoad = CreateRenderPass(targetInfo.colorFormat, depthStencilFormat, VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
if (target.renderPassLoad == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Array<VkImageView, 2> attachments{};
|
||||
attachments[0] = targetInfo.colorView;
|
||||
Uint32 attachmentCount = 1;
|
||||
if (hasDepthStencil) {
|
||||
attachments[1] = targetInfo.depthStencilView;
|
||||
attachmentCount = 2;
|
||||
}
|
||||
|
||||
VkFramebufferCreateInfo framebufferInfo{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
|
||||
framebufferInfo.renderPass = target.renderPassLoad;
|
||||
framebufferInfo.attachmentCount = attachmentCount;
|
||||
framebufferInfo.pAttachments = attachments.data();
|
||||
framebufferInfo.width = targetInfo.extent.width;
|
||||
framebufferInfo.height = targetInfo.extent.height;
|
||||
framebufferInfo.layers = 1;
|
||||
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &target.framebuffer),
|
||||
"vkCreateFramebuffer(offscreen)");
|
||||
|
||||
target.targetVersion = targetInfo.targetVersion;
|
||||
target.colorView = targetInfo.colorView;
|
||||
target.colorFormat = targetInfo.colorFormat;
|
||||
target.depthStencilView = targetInfo.depthStencilView;
|
||||
target.depthStencilFormat = targetInfo.depthStencilFormat;
|
||||
target.extent = targetInfo.extent;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkRenderPassManager::GetOffscreenRenderTarget(Uint targetExternalIndex, VkRenderPass& outRenderPass,
|
||||
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent,
|
||||
VkFormat& outDepthStencilFormat) const {
|
||||
auto it = m_offscreenRenderTargets.find(targetExternalIndex);
|
||||
if (it == m_offscreenRenderTargets.end() || it->second.renderPassLoad == VK_NULL_HANDLE ||
|
||||
it->second.framebuffer == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outRenderPass = it->second.renderPassLoad;
|
||||
outFramebuffer = it->second.framebuffer;
|
||||
outExtent = it->second.extent;
|
||||
outDepthStencilFormat = it->second.depthStencilFormat;
|
||||
return true;
|
||||
}
|
||||
|
||||
void VkRenderPassManager::RemoveOffscreenRenderTarget(Uint targetExternalIndex) {
|
||||
auto it = m_offscreenRenderTargets.find(targetExternalIndex);
|
||||
if (it == m_offscreenRenderTargets.end()) {
|
||||
return;
|
||||
}
|
||||
DestroyOffscreenRenderTarget(it->second);
|
||||
m_offscreenRenderTargets.erase(it);
|
||||
}
|
||||
|
||||
void VkRenderPassManager::BeginRenderPass(VkCommandBuffer commandBuffer, VkRenderPass renderPass,
|
||||
VkFramebuffer framebuffer, VkExtent2D extent) const {
|
||||
VkRenderPassBeginInfo beginInfo{};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
beginInfo.renderPass = renderPass;
|
||||
beginInfo.framebuffer = framebuffer;
|
||||
beginInfo.renderArea.offset = {0, 0};
|
||||
beginInfo.renderArea.extent = extent;
|
||||
beginInfo.clearValueCount = 0;
|
||||
beginInfo.pClearValues = nullptr;
|
||||
vkCmdBeginRenderPass(commandBuffer, &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
}
|
||||
|
||||
void VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) const {
|
||||
vkCmdEndRenderPass(commandBuffer);
|
||||
}
|
||||
|
||||
void VkRenderPassManager::RecordColorClear(VkCommandBuffer commandBuffer, VkExtent2D extent,
|
||||
const VkClearColorValue& clearColor) const {
|
||||
VkClearAttachment clearAttachment{};
|
||||
clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
clearAttachment.colorAttachment = 0;
|
||||
clearAttachment.clearValue.color = clearColor;
|
||||
|
||||
VkClearRect clearRect{};
|
||||
clearRect.rect.offset = {0, 0};
|
||||
clearRect.rect.extent = extent;
|
||||
clearRect.baseArrayLayer = 0;
|
||||
clearRect.layerCount = 1;
|
||||
|
||||
vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect);
|
||||
}
|
||||
|
||||
void VkRenderPassManager::RecordDepthStencilClear(VkCommandBuffer commandBuffer, VkExtent2D extent, GLbitfield mask,
|
||||
Float depth, Uint32 stencil, VkFormat depthStencilFormat) const {
|
||||
if (depthStencilFormat == VK_FORMAT_UNDEFINED) {
|
||||
return;
|
||||
}
|
||||
|
||||
VkImageAspectFlags aspectMask = 0;
|
||||
if ((mask & GL_DEPTH_BUFFER_BIT) != 0) {
|
||||
aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
}
|
||||
if ((mask & GL_STENCIL_BUFFER_BIT) != 0 && HasStencilComponent(depthStencilFormat)) {
|
||||
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
}
|
||||
if (aspectMask == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
VkClearAttachment clearAttachment{};
|
||||
clearAttachment.aspectMask = aspectMask;
|
||||
clearAttachment.clearValue.depthStencil.depth = depth;
|
||||
clearAttachment.clearValue.depthStencil.stencil = stencil;
|
||||
|
||||
VkClearRect clearRect{};
|
||||
clearRect.rect.offset = {0, 0};
|
||||
clearRect.rect.extent = extent;
|
||||
clearRect.baseArrayLayer = 0;
|
||||
clearRect.layerCount = 1;
|
||||
|
||||
vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect);
|
||||
}
|
||||
|
||||
VkRenderPass VkRenderPassManager::GetLoadRenderPass() const {
|
||||
return m_renderPassLoad;
|
||||
}
|
||||
|
||||
VkRenderPass VkRenderPassManager::GetClearRenderPass() const {
|
||||
return m_renderPassClear;
|
||||
}
|
||||
|
||||
VkRenderPass VkRenderPassManager::CreateDefaultRenderPass(VkAttachmentLoadOp colorLoadOp) const {
|
||||
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE, "VkRenderPassManager: device is null");
|
||||
MOBILEGL_ASSERT(m_colorFormat != VK_FORMAT_UNDEFINED, "VkRenderPassManager: color format is undefined");
|
||||
MOBILEGL_ASSERT(m_depthStencilFormat != VK_FORMAT_UNDEFINED,
|
||||
"VkRenderPassManager: depth/stencil format is undefined");
|
||||
return CreateRenderPass(m_colorFormat, m_depthStencilFormat, colorLoadOp, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
}
|
||||
|
||||
VkRenderPass VkRenderPassManager::CreateRenderPass(VkFormat colorFormat, VkFormat depthStencilFormat,
|
||||
VkAttachmentLoadOp colorLoadOp,
|
||||
VkImageLayout colorFinalLayout) const {
|
||||
VkAttachmentDescription color{};
|
||||
color.format = colorFormat;
|
||||
color.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
color.loadOp = colorLoadOp;
|
||||
color.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
color.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
color.finalLayout = colorFinalLayout;
|
||||
color.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
color.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
|
||||
const Bool hasDepthStencil = depthStencilFormat != VK_FORMAT_UNDEFINED;
|
||||
VkAttachmentDescription depthStencil{};
|
||||
if (hasDepthStencil) {
|
||||
depthStencil.format = depthStencilFormat;
|
||||
depthStencil.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
depthStencil.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
depthStencil.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
depthStencil.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
depthStencil.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
depthStencil.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
depthStencil.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
VkAttachmentReference colorRef{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
|
||||
VkAttachmentReference depthStencilRef{1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
|
||||
|
||||
VkSubpassDescription subpass{};
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &colorRef;
|
||||
if (hasDepthStencil) {
|
||||
subpass.pDepthStencilAttachment = &depthStencilRef;
|
||||
}
|
||||
|
||||
Array<VkAttachmentDescription, 2> attachments{};
|
||||
attachments[0] = color;
|
||||
Uint32 attachmentCount = 1;
|
||||
if (hasDepthStencil) {
|
||||
attachments[1] = depthStencil;
|
||||
attachmentCount = 2;
|
||||
}
|
||||
|
||||
VkRenderPassCreateInfo createInfo{VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO};
|
||||
createInfo.attachmentCount = attachmentCount;
|
||||
createInfo.pAttachments = attachments.data();
|
||||
createInfo.subpassCount = 1;
|
||||
createInfo.pSubpasses = &subpass;
|
||||
// Render Pass
|
||||
VkRenderPassCreateInfo renderPassCreateInfo;
|
||||
renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
renderPassCreateInfo.pNext = VK_NULL_HANDLE;
|
||||
renderPassCreateInfo.flags = 0;
|
||||
renderPassCreateInfo.attachmentCount = attachmentDescriptions.size();
|
||||
renderPassCreateInfo.pAttachments = attachmentDescriptions.data();
|
||||
renderPassCreateInfo.subpassCount = 1;
|
||||
renderPassCreateInfo.pSubpasses = &subpassDesc;
|
||||
renderPassCreateInfo.dependencyCount = 0;
|
||||
renderPassCreateInfo.pDependencies = nullptr;
|
||||
|
||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||
VK_VERIFY(vkCreateRenderPass(m_device, &createInfo, nullptr, &renderPass), "vkCreateRenderPass");
|
||||
return renderPass;
|
||||
VK_VERIFY(vkCreateRenderPass(m_device, &renderPassCreateInfo, nullptr, &renderPass));
|
||||
|
||||
// Framebuffer
|
||||
VkFramebufferCreateInfo framebufferCreateInfo;
|
||||
framebufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
framebufferCreateInfo.pNext = nullptr;
|
||||
framebufferCreateInfo.flags = 0;
|
||||
framebufferCreateInfo.renderPass = renderPass;
|
||||
framebufferCreateInfo.attachmentCount = attachmentViews.size();
|
||||
framebufferCreateInfo.pAttachments = attachmentViews.data();
|
||||
framebufferCreateInfo.width = width;
|
||||
framebufferCreateInfo.height = height;
|
||||
framebufferCreateInfo.layers = 1;
|
||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferCreateInfo, nullptr, &framebuffer));
|
||||
IntVec2 extent = {width, height};
|
||||
RenderPassEntry renderPassEntry {
|
||||
hash,
|
||||
renderPass,
|
||||
framebuffer,
|
||||
compatibilityHash,
|
||||
Move(pendingClearAttachments),
|
||||
Move(trackedAttachmentLayouts),
|
||||
static_cast<Uint32>(attachmentViews.size()),
|
||||
extent,
|
||||
1 };
|
||||
auto [insertedIt, _] = m_renderPasses.emplace(hash, Move(renderPassEntry));
|
||||
return insertedIt->second;
|
||||
}
|
||||
|
||||
void VkRenderPassManager::DestroyDefaultFramebuffers() {
|
||||
for (auto framebuffer : m_defaultFramebuffers) {
|
||||
if (framebuffer != VK_NULL_HANDLE) {
|
||||
vkDestroyFramebuffer(m_device, framebuffer, nullptr);
|
||||
Bool VkRenderPassManager::BeginRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry) {
|
||||
// TODO: Transition all the attachments into proper layout before starting the render pass
|
||||
VkRenderPassBeginInfo renderPassBeginInfo;
|
||||
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
renderPassBeginInfo.pNext = nullptr;
|
||||
renderPassBeginInfo.renderPass = renderPassEntry.renderPass;
|
||||
renderPassBeginInfo.framebuffer = renderPassEntry.framebuffer;
|
||||
renderPassBeginInfo.renderArea.offset = { 0, 0 };
|
||||
renderPassBeginInfo.renderArea.extent = {
|
||||
(Uint32)renderPassEntry.extent.x(), (Uint32)renderPassEntry.extent.y() };
|
||||
|
||||
Vector<VkClearValue> clearValues(renderPassEntry.attachmentCount);
|
||||
for (auto& clearValue: clearValues) {
|
||||
clearValue.color = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
clearValue.depthStencil = {1.0f, 0};
|
||||
}
|
||||
for (const auto& pending: renderPassEntry.pendingClearAttachments) {
|
||||
if (!pending.texture || pending.attachmentIndex >= clearValues.size()) {
|
||||
continue;
|
||||
}
|
||||
ClearAttachmentPayload clearPayload{};
|
||||
if (!s_clearManager->GetPendingClear(pending.texture, clearPayload)) {
|
||||
continue;
|
||||
}
|
||||
if (clearPayload.attachmentType >= FramebufferAttachmentType::Color0 &&
|
||||
clearPayload.attachmentType <= FramebufferAttachmentType::Color31) {
|
||||
clearValues[pending.attachmentIndex].color = {
|
||||
clearPayload.color.x(),
|
||||
clearPayload.color.y(),
|
||||
clearPayload.color.z(),
|
||||
clearPayload.color.w()
|
||||
};
|
||||
} else if (clearPayload.attachmentType == FramebufferAttachmentType::Depth) {
|
||||
clearValues[pending.attachmentIndex].depthStencil.depth = clearPayload.depth;
|
||||
} else if (clearPayload.attachmentType == FramebufferAttachmentType::Stencil) {
|
||||
clearValues[pending.attachmentIndex].depthStencil.stencil = clearPayload.stencil;
|
||||
}
|
||||
}
|
||||
m_defaultFramebuffers.clear();
|
||||
m_defaultExtent = {0, 0};
|
||||
|
||||
renderPassBeginInfo.clearValueCount = static_cast<Uint32>(clearValues.size());
|
||||
renderPassBeginInfo.pClearValues = clearValues.data();
|
||||
|
||||
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
for (const auto& pending: renderPassEntry.pendingClearAttachments) {
|
||||
s_clearManager->PopPendingClear(pending.texture);
|
||||
}
|
||||
s_activeRenderPass.hash = renderPassEntry.hash;
|
||||
s_activeRenderPass.compatibilityHash = renderPassEntry.compatibilityHash;
|
||||
s_activeRenderPass.trackedAttachmentLayouts = renderPassEntry.trackedAttachmentLayouts;
|
||||
s_activeRenderPass.extent = renderPassEntry.extent;
|
||||
s_hasActiveRenderPass = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VkRenderPassManager::DestroyOffscreenRenderTarget(OffscreenRenderTarget& target) {
|
||||
if (target.framebuffer != VK_NULL_HANDLE) {
|
||||
vkDestroyFramebuffer(m_device, target.framebuffer, nullptr);
|
||||
target.framebuffer = VK_NULL_HANDLE;
|
||||
Bool VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) {
|
||||
auto* activeRenderPass = GetActiveRenderPass();
|
||||
vkCmdEndRenderPass(commandBuffer);
|
||||
if (activeRenderPass != nullptr && !activeRenderPass->trackedAttachmentLayouts.empty()) {
|
||||
for (const auto& trackedAttachment : activeRenderPass->trackedAttachmentLayouts) {
|
||||
switch (trackedAttachment.target) {
|
||||
case TrackedAttachmentTarget::Texture:
|
||||
MOBILEGL_ASSERT(s_textureManager != nullptr, "EndRenderPass: texture manager is null");
|
||||
s_textureManager->UpdateTrackedImageLayout(trackedAttachment.texture, trackedAttachment.finalLayout);
|
||||
break;
|
||||
case TrackedAttachmentTarget::SwapchainColor:
|
||||
MOBILEGL_ASSERT(s_swapchainObject != nullptr, "EndRenderPass: swapchain object is null");
|
||||
s_swapchainObject->SetImageLayout(trackedAttachment.swapchainImageIndex, trackedAttachment.finalLayout);
|
||||
break;
|
||||
case TrackedAttachmentTarget::SwapchainDepthStencil:
|
||||
MOBILEGL_ASSERT(s_swapchainObject != nullptr, "EndRenderPass: swapchain object is null");
|
||||
s_swapchainObject->SetDepthStencilImageLayout(trackedAttachment.swapchainImageIndex,
|
||||
trackedAttachment.finalLayout);
|
||||
break;
|
||||
default:
|
||||
MOBILEGL_ASSERT(false, "EndRenderPass: unsupported tracked attachment target=%d",
|
||||
static_cast<Int>(trackedAttachment.target));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (target.renderPassLoad != VK_NULL_HANDLE) {
|
||||
vkDestroyRenderPass(m_device, target.renderPassLoad, nullptr);
|
||||
target.renderPassLoad = VK_NULL_HANDLE;
|
||||
}
|
||||
target.targetVersion = 0;
|
||||
target.colorView = VK_NULL_HANDLE;
|
||||
target.colorFormat = VK_FORMAT_UNDEFINED;
|
||||
target.depthStencilView = VK_NULL_HANDLE;
|
||||
target.depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
target.extent = {0, 0};
|
||||
s_activeRenderPass = {};
|
||||
s_hasActiveRenderPass = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkRenderPassManager::HasStencilComponent(VkFormat format) {
|
||||
return format == VK_FORMAT_D24_UNORM_S8_UINT || format == VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||
ActiveRenderPassInfo* VkRenderPassManager::GetActiveRenderPass() {
|
||||
return s_hasActiveRenderPass ? &s_activeRenderPass : nullptr;
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -8,79 +8,144 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SwapchainObject.h"
|
||||
#include "VkClearManager.h"
|
||||
#include "VkTextureManager.h"
|
||||
#include "../VkIncludes.h"
|
||||
#include "../VulkanRendererConfig.h"
|
||||
#include "MG_State/GLState/FramebufferState/FramebufferObject.h"
|
||||
|
||||
#include <Includes.h>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
enum class TrackedAttachmentTarget : Uint8 {
|
||||
Texture,
|
||||
SwapchainColor,
|
||||
SwapchainDepthStencil
|
||||
};
|
||||
|
||||
struct PendingClearAttachmentInfo {
|
||||
Uint32 attachmentIndex = 0;
|
||||
MG_State::GLState::ITextureObject* texture = nullptr;
|
||||
};
|
||||
|
||||
struct TrackedAttachmentLayoutInfo {
|
||||
TrackedAttachmentTarget target = TrackedAttachmentTarget::Texture;
|
||||
MG_State::GLState::ITextureObject* texture = nullptr;
|
||||
Uint32 swapchainImageIndex = 0;
|
||||
VkImageLayout finalLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
};
|
||||
|
||||
struct RenderPassEntry {
|
||||
static inline VkDevice s_device;
|
||||
static inline Vector<VkTextureManager::TextureResource*> s_textureResourcesScratch;
|
||||
Uint64 hash = 0;
|
||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||
Uint64 compatibilityHash = 0;
|
||||
Vector<PendingClearAttachmentInfo> pendingClearAttachments;
|
||||
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
|
||||
Uint32 attachmentCount = 0;
|
||||
IntVec2 extent = {0, 0};
|
||||
Uint32 subpass = 0;
|
||||
|
||||
RenderPassEntry() = default;
|
||||
RenderPassEntry(const RenderPassEntry&) = delete;
|
||||
RenderPassEntry(RenderPassEntry&& that) noexcept {
|
||||
std::swap(hash, that.hash);
|
||||
std::swap(renderPass, that.renderPass);
|
||||
std::swap(framebuffer, that.framebuffer);
|
||||
std::swap(compatibilityHash, that.compatibilityHash);
|
||||
std::swap(pendingClearAttachments, that.pendingClearAttachments);
|
||||
std::swap(trackedAttachmentLayouts, that.trackedAttachmentLayouts);
|
||||
std::swap(attachmentCount, that.attachmentCount);
|
||||
std::swap(extent, that.extent);
|
||||
std::swap(subpass, that.subpass);
|
||||
}
|
||||
RenderPassEntry(
|
||||
Uint64 hash,
|
||||
VkRenderPass renderpass,
|
||||
VkFramebuffer framebuffer,
|
||||
Uint64 compatibilityHash,
|
||||
const Vector<PendingClearAttachmentInfo>& pendingClearAttachments,
|
||||
const Vector<TrackedAttachmentLayoutInfo>& trackedAttachmentLayouts,
|
||||
Uint32 attachmentCount,
|
||||
IntVec2 extent, int subpass):
|
||||
hash(hash),
|
||||
renderPass(renderpass),
|
||||
framebuffer(framebuffer),
|
||||
compatibilityHash(compatibilityHash),
|
||||
pendingClearAttachments(Move(pendingClearAttachments)),
|
||||
trackedAttachmentLayouts(Move(trackedAttachmentLayouts)),
|
||||
attachmentCount(attachmentCount),
|
||||
extent(extent),
|
||||
subpass(subpass)
|
||||
{}
|
||||
|
||||
~RenderPassEntry() {
|
||||
if (renderPass != VK_NULL_HANDLE) {
|
||||
vkDestroyRenderPass(s_device, renderPass, nullptr);
|
||||
}
|
||||
if (framebuffer != VK_NULL_HANDLE) {
|
||||
vkDestroyFramebuffer(s_device, framebuffer, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
Bool CompatibleWith(const RenderPassEntry& that) const {
|
||||
return this->compatibilityHash == that.compatibilityHash;
|
||||
}
|
||||
|
||||
Bool CompatibleWith(Uint64 compatibilityHash) const {
|
||||
return this->compatibilityHash == compatibilityHash;
|
||||
}
|
||||
};
|
||||
|
||||
struct ActiveRenderPassInfo {
|
||||
Uint64 hash = 0;
|
||||
Uint64 compatibilityHash = 0;
|
||||
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
|
||||
IntVec2 extent = {0, 0};
|
||||
|
||||
Bool CompatibleWith(const RenderPassEntry& that) const {
|
||||
return compatibilityHash == that.compatibilityHash;
|
||||
}
|
||||
|
||||
Bool CompatibleWith(Uint64 thatCompatibilityHash) const {
|
||||
return compatibilityHash == thatCompatibilityHash;
|
||||
}
|
||||
};
|
||||
|
||||
class VkRenderPassManager {
|
||||
public:
|
||||
struct InitInfo {
|
||||
VkDevice device = VK_NULL_HANDLE;
|
||||
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
|
||||
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
};
|
||||
using HashType = Uint64;
|
||||
VkRenderPassManager(VkDevice device,
|
||||
const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager,
|
||||
SwapchainObject& swapchainObject);
|
||||
~VkRenderPassManager();
|
||||
|
||||
struct OffscreenRenderTargetInfo {
|
||||
Uint targetExternalIndex = 0;
|
||||
Uint16 targetVersion = 0;
|
||||
VkImageView colorView = VK_NULL_HANDLE;
|
||||
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
|
||||
VkImageView depthStencilView = VK_NULL_HANDLE;
|
||||
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
VkExtent2D extent = {0, 0};
|
||||
};
|
||||
|
||||
Bool Initialize(const InitInfo& initInfo);
|
||||
Bool Initialize();
|
||||
void Shutdown();
|
||||
|
||||
Bool RecreateDefaultFramebuffers(const Vector<VkImageView>& colorViews,
|
||||
const Vector<VkImageView>& depthStencilViews, VkExtent2D extent);
|
||||
Bool GetDefaultRenderTarget(Uint32 imageIndex, VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer,
|
||||
VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) const;
|
||||
|
||||
Bool EnsureOffscreenRenderTarget(const OffscreenRenderTargetInfo& targetInfo);
|
||||
Bool GetOffscreenRenderTarget(Uint targetExternalIndex, VkRenderPass& outRenderPass,
|
||||
VkFramebuffer& outFramebuffer, VkExtent2D& outExtent,
|
||||
VkFormat& outDepthStencilFormat) const;
|
||||
void RemoveOffscreenRenderTarget(Uint targetExternalIndex);
|
||||
|
||||
void BeginRenderPass(VkCommandBuffer commandBuffer, VkRenderPass renderPass, VkFramebuffer framebuffer,
|
||||
VkExtent2D extent) const;
|
||||
void EndRenderPass(VkCommandBuffer commandBuffer) const;
|
||||
void RecordColorClear(VkCommandBuffer commandBuffer, VkExtent2D extent,
|
||||
const VkClearColorValue& clearColor) const;
|
||||
void RecordDepthStencilClear(VkCommandBuffer commandBuffer, VkExtent2D extent, GLbitfield mask, Float depth,
|
||||
Uint32 stencil, VkFormat depthStencilFormat) const;
|
||||
|
||||
VkRenderPass GetLoadRenderPass() const;
|
||||
VkRenderPass GetClearRenderPass() const;
|
||||
|
||||
HashType ComputeHash(
|
||||
const MG_State::GLState::FramebufferObject& fbo,
|
||||
Uint32 swapchainImageIndex,
|
||||
Bool includePendingClear = true) const;
|
||||
RenderPassEntry& GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo, Uint32 swapchainImageIndex);
|
||||
static Bool BeginRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry);
|
||||
static Bool EndRenderPass(VkCommandBuffer commandBuffer);
|
||||
static ActiveRenderPassInfo* GetActiveRenderPass();
|
||||
private:
|
||||
struct OffscreenRenderTarget {
|
||||
Uint16 targetVersion = 0;
|
||||
VkImageView colorView = VK_NULL_HANDLE;
|
||||
VkFormat colorFormat = VK_FORMAT_UNDEFINED;
|
||||
VkImageView depthStencilView = VK_NULL_HANDLE;
|
||||
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
VkExtent2D extent = {0, 0};
|
||||
VkRenderPass renderPassLoad = VK_NULL_HANDLE;
|
||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
VkRenderPass CreateDefaultRenderPass(VkAttachmentLoadOp colorLoadOp) const;
|
||||
VkRenderPass CreateRenderPass(VkFormat colorFormat, VkFormat depthStencilFormat, VkAttachmentLoadOp colorLoadOp,
|
||||
VkImageLayout colorFinalLayout) const;
|
||||
void DestroyDefaultFramebuffers();
|
||||
void DestroyOffscreenRenderTarget(OffscreenRenderTarget& target);
|
||||
static Bool HasStencilComponent(VkFormat format);
|
||||
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
VkFormat m_colorFormat = VK_FORMAT_UNDEFINED;
|
||||
VkFormat m_depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
VkRenderPass m_renderPassLoad = VK_NULL_HANDLE;
|
||||
VkRenderPass m_renderPassClear = VK_NULL_HANDLE;
|
||||
Vector<VkFramebuffer> m_defaultFramebuffers;
|
||||
VkExtent2D m_defaultExtent = {0, 0};
|
||||
UnorderedMap<Uint, OffscreenRenderTarget> m_offscreenRenderTargets;
|
||||
const VulkanRendererConfig& m_config;
|
||||
VkClearManager& m_clearManager;
|
||||
VkTextureManager& m_textureManager;
|
||||
SwapchainObject& m_swapchainObject;
|
||||
UnorderedMap<Uint64, RenderPassEntry> m_renderPasses;
|
||||
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
||||
static inline ActiveRenderPassInfo s_activeRenderPass{};
|
||||
static inline Bool s_hasActiveRenderPass = false;
|
||||
static inline VkClearManager* s_clearManager = nullptr;
|
||||
static inline VkTextureManager* s_textureManager = nullptr;
|
||||
static inline SwapchainObject* s_swapchainObject = nullptr;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkSamplerManager.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "VkSamplerManager.h"
|
||||
|
||||
#include "MG_State/GLState/Core.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool VkSamplerManager::Initialize(const InitInfo& initInfo) {
|
||||
Shutdown();
|
||||
|
||||
m_device = initInfo.device;
|
||||
m_config = initInfo.config;
|
||||
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE && m_config != nullptr,
|
||||
"VkSamplerManager::Initialize failed: invalid initialization info");
|
||||
return true;
|
||||
}
|
||||
|
||||
void VkSamplerManager::Shutdown() {
|
||||
for (auto& [_, sampler] : m_samplers) {
|
||||
if (m_device != VK_NULL_HANDLE && sampler.handle != VK_NULL_HANDLE) {
|
||||
vkDestroySampler(m_device, sampler.handle, nullptr);
|
||||
}
|
||||
sampler.handle = VK_NULL_HANDLE;
|
||||
}
|
||||
m_samplers.clear();
|
||||
|
||||
m_device = VK_NULL_HANDLE;
|
||||
m_config = nullptr;
|
||||
}
|
||||
|
||||
Uint64 VkSamplerManager::BuildSamplerKey(const MG_State::GLState::SamplerObject& sampler) const {
|
||||
MOBILEGL_ASSERT(m_config != nullptr, "VkSamplerManager::BuildSamplerKey: m_config is null");
|
||||
XXHASH_VERIFY(XXH64_reset(m_hashState, m_config->CacheVersion));
|
||||
|
||||
const auto minFilter = sampler.GetMinFilter();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &minFilter, sizeof(minFilter)));
|
||||
const auto magFilter = sampler.GetMagFilter();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &magFilter, sizeof(magFilter)));
|
||||
const auto mipmapMode = sampler.GetMipmapMode();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &mipmapMode, sizeof(mipmapMode)));
|
||||
const auto wrapS = sampler.GetWrapS();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &wrapS, sizeof(wrapS)));
|
||||
const auto wrapT = sampler.GetWrapT();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &wrapT, sizeof(wrapT)));
|
||||
const auto wrapR = sampler.GetWrapR();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &wrapR, sizeof(wrapR)));
|
||||
const auto minLod = sampler.GetMinLod();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &minLod, sizeof(minLod)));
|
||||
const auto maxLod = sampler.GetMaxLod();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &maxLod, sizeof(maxLod)));
|
||||
const auto lodBias = sampler.GetLodBias();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &lodBias, sizeof(lodBias)));
|
||||
const auto compareMode = sampler.GetCompareMode();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &compareMode, sizeof(compareMode)));
|
||||
const auto compareFunc = sampler.GetSamplerCompareFunc();
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &compareFunc, sizeof(compareFunc)));
|
||||
return XXH64_digest(m_hashState);
|
||||
}
|
||||
|
||||
VkSampler VkSamplerManager::GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler) {
|
||||
const Uint64 key = BuildSamplerKey(sampler);
|
||||
auto it = m_samplers.find(key);
|
||||
if (it != m_samplers.end()) {
|
||||
return it->second.handle;
|
||||
}
|
||||
|
||||
VkSamplerCreateInfo samplerInfo{};
|
||||
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||
samplerInfo.magFilter = ToVkFilter(sampler.GetMagFilter());
|
||||
samplerInfo.minFilter = ToVkFilter(sampler.GetMinFilter());
|
||||
samplerInfo.mipmapMode = ToVkMipmapMode(sampler.GetMipmapMode());
|
||||
samplerInfo.addressModeU = ToVkAddressMode(sampler.GetWrapS());
|
||||
samplerInfo.addressModeV = ToVkAddressMode(sampler.GetWrapT());
|
||||
samplerInfo.addressModeW = ToVkAddressMode(sampler.GetWrapR());
|
||||
samplerInfo.mipLodBias = sampler.GetLodBias();
|
||||
samplerInfo.anisotropyEnable = VK_FALSE;
|
||||
samplerInfo.maxAnisotropy = 1.0f;
|
||||
samplerInfo.compareEnable = sampler.GetCompareMode() == SamplerCompareMode::CompareToTexture ? VK_TRUE : VK_FALSE;
|
||||
samplerInfo.compareOp = ToVkCompareOp(sampler.GetSamplerCompareFunc());
|
||||
samplerInfo.minLod = sampler.GetMinLod();
|
||||
samplerInfo.maxLod = sampler.GetMaxLod();
|
||||
samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
||||
samplerInfo.unnormalizedCoordinates = VK_FALSE;
|
||||
|
||||
VkSampler vkSampler = VK_NULL_HANDLE;
|
||||
VK_VERIFY(vkCreateSampler(m_device, &samplerInfo, nullptr, &vkSampler), "vkCreateSampler(texture)");
|
||||
|
||||
SamplerCacheEntry entry{};
|
||||
entry.handle = vkSampler;
|
||||
entry.externalIndex = sampler.GetExternalIndex();
|
||||
entry.version = sampler.GetVersion();
|
||||
m_samplers[key] = entry;
|
||||
return vkSampler;
|
||||
}
|
||||
|
||||
VkFilter VkSamplerManager::ToVkFilter(SamplerFilterMode mode) {
|
||||
return mode == SamplerFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;
|
||||
}
|
||||
|
||||
VkSamplerMipmapMode VkSamplerManager::ToVkMipmapMode(SamplerMipmapMode mode) {
|
||||
switch (mode) {
|
||||
case SamplerMipmapMode::Nearest:
|
||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
case SamplerMipmapMode::Linear:
|
||||
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
case SamplerMipmapMode::None:
|
||||
default:
|
||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
}
|
||||
}
|
||||
|
||||
VkSamplerAddressMode VkSamplerManager::ToVkAddressMode(SamplerWrapMode mode) {
|
||||
switch (mode) {
|
||||
case SamplerWrapMode::ClampToEdge:
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
case SamplerWrapMode::MirroredRepeat:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
||||
case SamplerWrapMode::Repeat:
|
||||
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
case SamplerWrapMode::ClampToBorder:
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||
case SamplerWrapMode::MirrorClampToEdge:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
|
||||
default:
|
||||
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
}
|
||||
}
|
||||
|
||||
VkCompareOp VkSamplerManager::ToVkCompareOp(SamplerCompareFunc func) {
|
||||
switch (func) {
|
||||
case SamplerCompareFunc::Never:
|
||||
return VK_COMPARE_OP_NEVER;
|
||||
case SamplerCompareFunc::Less:
|
||||
return VK_COMPARE_OP_LESS;
|
||||
case SamplerCompareFunc::Equal:
|
||||
return VK_COMPARE_OP_EQUAL;
|
||||
case SamplerCompareFunc::LessEqual:
|
||||
return VK_COMPARE_OP_LESS_OR_EQUAL;
|
||||
case SamplerCompareFunc::Greater:
|
||||
return VK_COMPARE_OP_GREATER;
|
||||
case SamplerCompareFunc::NotEqual:
|
||||
return VK_COMPARE_OP_NOT_EQUAL;
|
||||
case SamplerCompareFunc::GreaterEqual:
|
||||
return VK_COMPARE_OP_GREATER_OR_EQUAL;
|
||||
case SamplerCompareFunc::Always:
|
||||
default:
|
||||
return VK_COMPARE_OP_ALWAYS;
|
||||
}
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -0,0 +1,51 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkSamplerManager.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../VkIncludes.h"
|
||||
#include "../VulkanRendererConfig.h"
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/SamplerState/SamplerObject.h>
|
||||
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
class SamplerObject;
|
||||
}
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
class VkSamplerManager {
|
||||
public:
|
||||
struct InitInfo {
|
||||
VkDevice device = VK_NULL_HANDLE;
|
||||
const VulkanRendererConfig* config = nullptr;
|
||||
};
|
||||
|
||||
Bool Initialize(const InitInfo& initInfo);
|
||||
void Shutdown();
|
||||
|
||||
VkSampler GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler);
|
||||
|
||||
private:
|
||||
struct SamplerCacheEntry {
|
||||
VkSampler handle = VK_NULL_HANDLE;
|
||||
Uint externalIndex = 0;
|
||||
Uint16 version = 0;
|
||||
};
|
||||
|
||||
Uint64 BuildSamplerKey(const MG_State::GLState::SamplerObject& sampler) const;
|
||||
static VkFilter ToVkFilter(SamplerFilterMode mode);
|
||||
static VkSamplerMipmapMode ToVkMipmapMode(SamplerMipmapMode mode);
|
||||
static VkSamplerAddressMode ToVkAddressMode(SamplerWrapMode mode);
|
||||
static VkCompareOp ToVkCompareOp(SamplerCompareFunc func);
|
||||
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
const VulkanRendererConfig* m_config = nullptr;
|
||||
UnorderedMap<Uint64, SamplerCacheEntry> m_samplers;
|
||||
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -0,0 +1,526 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "VkTextureManager.h"
|
||||
|
||||
#include "MG_State/GLState/Core.h"
|
||||
#include "MG_Util/Converters/MGToVk/TextureEnumConverter.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
static constexpr VkPipelineStageFlags kGraphicsSampledReadStages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
|
||||
|
||||
static Bool IsValidSampledImageLayout(VkImageLayout layout) {
|
||||
switch (layout) {
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
case VK_IMAGE_LAYOUT_GENERAL:
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
|
||||
case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Bool VkTextureManager::Initialize(const InitInfo& initInfo) {
|
||||
Shutdown();
|
||||
|
||||
m_device = initInfo.device;
|
||||
m_physicalDevice = initInfo.physicalDevice;
|
||||
m_allocator = initInfo.allocator;
|
||||
m_commandPool = initInfo.commandPool;
|
||||
m_graphicsQueue = initInfo.graphicsQueue;
|
||||
|
||||
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE && m_physicalDevice != VK_NULL_HANDLE && m_allocator != nullptr &&
|
||||
m_commandPool != VK_NULL_HANDLE && m_graphicsQueue != VK_NULL_HANDLE,
|
||||
"VkTextureManager::Initialize failed: invalid initialization info");
|
||||
|
||||
TextureResource::s_device = m_device;
|
||||
TextureResource::s_allocator = m_allocator;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VkTextureManager::Shutdown() {
|
||||
m_textureResources.clear();
|
||||
|
||||
m_device = VK_NULL_HANDLE;
|
||||
m_physicalDevice = VK_NULL_HANDLE;
|
||||
m_allocator = nullptr;
|
||||
m_commandPool = VK_NULL_HANDLE;
|
||||
m_graphicsQueue = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VkTextureManager::TextureResource* VkTextureManager::SyncTextureAndGetDescriptor(MG_State::GLState::ITextureObject& texture) {
|
||||
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE, "SyncTextureAndGetDescriptor: m_device == VK_NULL_HANDLE");
|
||||
|
||||
auto it = m_textureResources.find(&texture);
|
||||
if (it == m_textureResources.end()) {
|
||||
TextureResource initial{};
|
||||
auto [insertIt, _] = m_textureResources.emplace(&texture, Move(initial));
|
||||
it = insertIt;
|
||||
}
|
||||
|
||||
if (!SyncTexture(texture, it->second)) {
|
||||
MGLOG_D("%s: Syncing texture %d failed", __func__, texture.GetExternalIndex());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &(it->second);
|
||||
}
|
||||
|
||||
void VkTextureManager::UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout) {
|
||||
MOBILEGL_ASSERT(texture != nullptr, "UpdateTrackedImageLayout: texture is null");
|
||||
auto it = m_textureResources.find(texture);
|
||||
MOBILEGL_ASSERT(it != m_textureResources.end(),
|
||||
"UpdateTrackedImageLayout: textureId=%d has no tracked resource", texture->GetExternalIndex());
|
||||
MOBILEGL_ASSERT(it->second.image != VK_NULL_HANDLE,
|
||||
"UpdateTrackedImageLayout: textureId=%d has null image", texture->GetExternalIndex());
|
||||
it->second.layout = newLayout;
|
||||
}
|
||||
|
||||
Bool VkTextureManager::TransitionTextureForSampling(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture) {
|
||||
TextureResource* resource = SyncTextureAndGetDescriptor(texture);
|
||||
if (resource == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (IsValidSampledImageLayout(resource->layout)) {
|
||||
return true;
|
||||
}
|
||||
if (resource->layout == VK_IMAGE_LAYOUT_UNDEFINED) {
|
||||
MGLOG_W("TransitionTextureForSampling: textureId=%d is still in VK_IMAGE_LAYOUT_UNDEFINED before sampling",
|
||||
texture.GetExternalIndex());
|
||||
}
|
||||
|
||||
VkImageLayout targetLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
VkAccessFlags srcAccessMask = 0;
|
||||
if ((resource->aspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
|
||||
MOBILEGL_ASSERT(resource->layout == VK_IMAGE_LAYOUT_UNDEFINED ||
|
||||
resource->layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
"TransitionTextureForSampling: unsupported color layout=%d for textureId=%d",
|
||||
static_cast<Int>(resource->layout), texture.GetExternalIndex());
|
||||
if (resource->layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
||||
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
}
|
||||
targetLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
} else if ((resource->aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) {
|
||||
MOBILEGL_ASSERT(resource->layout == VK_IMAGE_LAYOUT_UNDEFINED ||
|
||||
resource->layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
"TransitionTextureForSampling: unsupported depth/stencil layout=%d for textureId=%d",
|
||||
static_cast<Int>(resource->layout), texture.GetExternalIndex());
|
||||
if (resource->layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
||||
srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
}
|
||||
targetLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
|
||||
} else {
|
||||
MOBILEGL_ASSERT(false, "TransitionTextureForSampling: unsupported aspect mask=0x%x for textureId=%d",
|
||||
static_cast<Uint32>(resource->aspect), texture.GetExternalIndex());
|
||||
}
|
||||
|
||||
const Bool ok = TransitionImageLayout(commandBuffer, resource->image, resource->layout, targetLayout, srcStageMask,
|
||||
kGraphicsSampledReadStages, srcAccessMask,
|
||||
VK_ACCESS_SHADER_READ_BIT, resource->aspect);
|
||||
MOBILEGL_ASSERT(ok, "TransitionTextureForSampling: transition failed for textureId=%d", texture.GetExternalIndex());
|
||||
return ok;
|
||||
}
|
||||
|
||||
Bool VkTextureManager::TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image,
|
||||
VkImageLayout& trackedLayout, VkImageLayout newLayout,
|
||||
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
|
||||
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask,
|
||||
VkImageAspectFlags aspectMask) {
|
||||
MOBILEGL_ASSERT(image != VK_NULL_HANDLE, "TransitionImageLayout: m_image == VK_NULL_HANDLE");
|
||||
MOBILEGL_ASSERT(!((dstAccessMask & VK_ACCESS_TRANSFER_READ_BIT) != 0 &&
|
||||
(dstStageMask & VK_PIPELINE_STAGE_TRANSFER_BIT) == 0),
|
||||
"TransitionImageLayout: invalid dstAccess/dstStage pair (dstAccess=0x%x, dstStage=0x%x, oldLayout=%d, newLayout=%d)",
|
||||
static_cast<Uint32>(dstAccessMask), static_cast<Uint32>(dstStageMask), static_cast<Int>(trackedLayout),
|
||||
static_cast<Int>(newLayout));
|
||||
|
||||
if (trackedLayout == newLayout) {
|
||||
return true;
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.srcAccessMask = srcAccessMask;
|
||||
barrier.dstAccessMask = dstAccessMask;
|
||||
barrier.oldLayout = trackedLayout;
|
||||
barrier.newLayout = newLayout;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = image;
|
||||
barrier.subresourceRange.aspectMask = aspectMask;
|
||||
barrier.subresourceRange.baseMipLevel = 0;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
vkCmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
|
||||
trackedLayout = newLayout;
|
||||
return true;
|
||||
}
|
||||
|
||||
SizeT VkTextureManager::CollectGarbage() {
|
||||
m_gcCounter++;
|
||||
if (m_gcCounter != 0) {
|
||||
return 0;
|
||||
}
|
||||
SizeT count = 0;
|
||||
for (const auto& [raw, weak]: m_aliveObjects) {
|
||||
if (weak.expired()) {
|
||||
count++;
|
||||
m_textureResources.erase(raw);
|
||||
m_aliveObjects.erase(raw);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
Bool VkTextureManager::SyncTexture(MG_State::GLState::ITextureObject &texture,
|
||||
TextureResource &outResource) {
|
||||
TextureUploadTarget uploadTarget = TextureUploadTarget::Unknown;
|
||||
IntVec3 texelSize{0, 0, 0};
|
||||
SizeT byteSize = 0;
|
||||
Uint32 mipLevelCount = 0;
|
||||
if (!CheckMipmapCompleteness(texture, uploadTarget, texelSize, byteSize, mipLevelCount)) {
|
||||
MGLOG_D("%s: mipmap not complete", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* mipTexture = dynamic_cast<MG_State::GLState::TextureObjectMipmap*>(&texture);
|
||||
if (!mipTexture) {
|
||||
MGLOG_D("%s: not TextureObjectMipmap", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SyncTextureResource(texture, uploadTarget, texelSize, byteSize, mipLevelCount, outResource)) {
|
||||
MGLOG_D("%s: SyncTextureResource failed", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
Bool hasDirtyMipLevel = false;
|
||||
for (Uint32 level = 0; level < mipLevelCount; ++level) {
|
||||
if (mipTexture->IsStorageDirty(uploadTarget, level)) {
|
||||
hasDirtyMipLevel = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasDirtyMipLevel) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!UploadDirtyMipLevels(*mipTexture, uploadTarget, outResource)) {
|
||||
MGLOG_D("%s: UploadDirtyMipLevels failed", __func__);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkTextureManager::SyncTextureResource(const MG_State::GLState::ITextureObject &texture,
|
||||
TextureUploadTarget uploadTarget,
|
||||
const IntVec3 &texelSize, SizeT byteSize, Uint32 mipLevels,
|
||||
TextureResource &resource) {
|
||||
const VkFormat format = MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat());
|
||||
if (format == VK_FORMAT_UNDEFINED) {
|
||||
MGLOG_D("%s: format == VK_FORMAT_UNDEFINED", __func__);
|
||||
return false;
|
||||
}
|
||||
if (texelSize.x() <= 0 || texelSize.y() <= 0 /*|| byteSize == 0*/) {
|
||||
MGLOG_D("%s: texelSize or byteSize is zero", __func__);
|
||||
return false;
|
||||
}
|
||||
if (mipLevels == 0) {
|
||||
MGLOG_D("%s: no mip levels", __func__);
|
||||
return false;
|
||||
}
|
||||
if (uploadTarget != TextureUploadTarget::Texture2D) {
|
||||
MGLOG_D("%s: not Texture2D, unsupported", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
const Bool compatible = resource.image != VK_NULL_HANDLE && resource.format == format &&
|
||||
resource.extent.width == static_cast<Uint32>(texelSize.x()) &&
|
||||
resource.extent.height == static_cast<Uint32>(texelSize.y()) &&
|
||||
resource.mipLevels == mipLevels;
|
||||
if (compatible) {
|
||||
return true;
|
||||
}
|
||||
|
||||
resource.Reset();
|
||||
|
||||
auto aspect = GetAspectMaskForFormat(format);
|
||||
|
||||
VkImageCreateInfo imageInfo{};
|
||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.extent.width = static_cast<Uint32>(texelSize.x());
|
||||
imageInfo.extent.height = static_cast<Uint32>(texelSize.y());
|
||||
imageInfo.extent.depth = 1;
|
||||
imageInfo.mipLevels = mipLevels;
|
||||
imageInfo.arrayLayers = 1;
|
||||
imageInfo.format = format;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageInfo.usage =
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
||||
((aspect & VK_IMAGE_ASPECT_COLOR_BIT) ?
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT : 0) |
|
||||
((aspect & VK_IMAGE_ASPECT_DEPTH_BIT || aspect & VK_IMAGE_ASPECT_STENCIL_BIT) ?
|
||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT : 0);
|
||||
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VmaAllocationCreateInfo allocationInfo{};
|
||||
allocationInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||
allocationInfo.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
VK_VERIFY(vmaCreateImage(m_allocator, &imageInfo, &allocationInfo, &resource.image, &resource.allocation, nullptr),
|
||||
"vmaCreateImage(texture)");
|
||||
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = resource.image;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = format;
|
||||
viewInfo.subresourceRange.aspectMask = aspect;
|
||||
viewInfo.subresourceRange.baseMipLevel = 0;
|
||||
viewInfo.subresourceRange.levelCount = mipLevels;
|
||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
viewInfo.subresourceRange.layerCount = 1;
|
||||
VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &resource.view), "vkCreateImageView(texture)");
|
||||
|
||||
resource.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
resource.extent = {static_cast<Uint32>(texelSize.x()), static_cast<Uint32>(texelSize.y())};
|
||||
resource.mipLevels = mipLevels;
|
||||
resource.format = format;
|
||||
resource.aspect = viewInfo.subresourceRange.aspectMask;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkTextureManager::UploadDirtyMipLevels(MG_State::GLState::TextureObjectMipmap &mipmapTexture,
|
||||
TextureUploadTarget uploadTarget,
|
||||
TextureResource &outResource) {
|
||||
struct UploadItem {
|
||||
Uint32 level = 0;
|
||||
SizeT byteSize = 0;
|
||||
IntVec3 texelSize = {0, 0, 0};
|
||||
const void* source = nullptr;
|
||||
VkDeviceSize offset = 0;
|
||||
};
|
||||
|
||||
Vector<UploadItem> uploadItems;
|
||||
uploadItems.reserve(outResource.mipLevels);
|
||||
|
||||
VkDeviceSize stagingSize = 0;
|
||||
for (Uint32 level = 0; level < outResource.mipLevels; ++level) {
|
||||
if (!mipmapTexture.IsStorageDirty(uploadTarget, level)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto texelSize = mipmapTexture.GetMipmapTexelSize(uploadTarget, level);
|
||||
const auto byteSize = mipmapTexture.GetMipmapByteSize(uploadTarget, level);
|
||||
if (texelSize.x() <= 0 || texelSize.y() <= 0 || byteSize == 0) {
|
||||
mipmapTexture.MarkStorageDirty(uploadTarget, level, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
const void* source = mipmapTexture.MapMipmapData(uploadTarget, level);
|
||||
if (source == nullptr) {
|
||||
MGLOG_D("%s: MapmipmapData failed at level %d", __func__, level);
|
||||
return false;
|
||||
}
|
||||
|
||||
uploadItems.push_back({level, byteSize, texelSize, source, stagingSize});
|
||||
stagingSize += static_cast<VkDeviceSize>(byteSize);
|
||||
}
|
||||
|
||||
if (uploadItems.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
VkBuffer stagingBuffer = VK_NULL_HANDLE;
|
||||
VmaAllocation stagingAllocation = nullptr;
|
||||
|
||||
VkBufferCreateInfo bufferInfo{};
|
||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
bufferInfo.size = stagingSize;
|
||||
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VmaAllocationCreateInfo stagingAllocationInfo{};
|
||||
stagingAllocationInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
|
||||
stagingAllocationInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||
stagingAllocationInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
VK_VERIFY(vmaCreateBuffer(m_allocator, &bufferInfo, &stagingAllocationInfo, &stagingBuffer, &stagingAllocation, nullptr),
|
||||
"vmaCreateBuffer(staging texture)");
|
||||
|
||||
void* mapped = nullptr;
|
||||
VK_VERIFY(vmaMapMemory(m_allocator, stagingAllocation, &mapped), "vmaMapMemory(staging texture)");
|
||||
for (const auto& item : uploadItems) {
|
||||
std::memcpy(static_cast<Uint8*>(mapped) + item.offset, item.source, item.byteSize);
|
||||
}
|
||||
vmaUnmapMemory(m_allocator, stagingAllocation);
|
||||
|
||||
VkCommandBufferAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocInfo.commandPool = m_commandPool;
|
||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
allocInfo.commandBufferCount = 1;
|
||||
|
||||
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
|
||||
VK_VERIFY(vkAllocateCommandBuffers(m_device, &allocInfo, &commandBuffer), "vkAllocateCommandBuffers(texture)");
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo{};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
VK_VERIFY(vkBeginCommandBuffer(commandBuffer, &beginInfo), "vkBeginCommandBuffer(texture)");
|
||||
|
||||
const VkImageAspectFlags aspectMask = GetAspectMaskForFormat(outResource.format);
|
||||
Bool ok = TransitionImageLayout(commandBuffer, outResource.image,
|
||||
outResource.layout,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
outResource.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ?
|
||||
kGraphicsSampledReadStages :
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
outResource.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ? VK_ACCESS_SHADER_READ_BIT : 0,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
aspectMask);
|
||||
MOBILEGL_ASSERT(ok, "TransitionImageLayout to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL failed");
|
||||
|
||||
for (const auto& item : uploadItems) {
|
||||
VkBufferImageCopy copy{};
|
||||
copy.bufferOffset = item.offset;
|
||||
copy.bufferRowLength = 0;
|
||||
copy.bufferImageHeight = 0;
|
||||
copy.imageSubresource.aspectMask = aspectMask;
|
||||
copy.imageSubresource.mipLevel = item.level;
|
||||
copy.imageSubresource.baseArrayLayer = 0;
|
||||
copy.imageSubresource.layerCount = 1;
|
||||
copy.imageOffset = {0, 0, 0};
|
||||
copy.imageExtent = {static_cast<Uint32>(item.texelSize.x()), static_cast<Uint32>(item.texelSize.y()), 1};
|
||||
vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, outResource.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1, ©);
|
||||
}
|
||||
|
||||
ok = TransitionImageLayout(commandBuffer, outResource.image,
|
||||
outResource.layout,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
kGraphicsSampledReadStages,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT,
|
||||
aspectMask);
|
||||
MOBILEGL_ASSERT(ok, "TransitionImageLayout to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL failed");
|
||||
outResource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
|
||||
VK_VERIFY(vkEndCommandBuffer(commandBuffer), "vkEndCommandBuffer(texture)");
|
||||
|
||||
VkSubmitInfo submitInfo{};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &commandBuffer;
|
||||
|
||||
VkFenceCreateInfo fenceInfo{};
|
||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
VkFence uploadFence = VK_NULL_HANDLE;
|
||||
VK_VERIFY(vkCreateFence(m_device, &fenceInfo, nullptr, &uploadFence), "vkCreateFence(texture upload)");
|
||||
|
||||
VK_VERIFY(vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, uploadFence), "vkQueueSubmit(texture)");
|
||||
VK_VERIFY(vkWaitForFences(m_device, 1, &uploadFence, VK_TRUE, UINT64_MAX), "vkWaitForFences(texture upload)");
|
||||
vkDestroyFence(m_device, uploadFence, nullptr);
|
||||
vkFreeCommandBuffers(m_device, m_commandPool, 1, &commandBuffer);
|
||||
|
||||
vmaDestroyBuffer(m_allocator, stagingBuffer, stagingAllocation);
|
||||
|
||||
if (!ok) {
|
||||
MGLOG_D("%s: texture upload cmd failed", __func__);
|
||||
return false;
|
||||
}
|
||||
for (const auto& item : uploadItems) {
|
||||
mipmapTexture.MarkStorageDirty(uploadTarget, item.level, false);
|
||||
}
|
||||
outResource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkTextureManager::CheckMipmapCompleteness(const MG_State::GLState::ITextureObject& texture,
|
||||
TextureUploadTarget& outTarget,
|
||||
IntVec3& outTexelSize,
|
||||
SizeT& outByteSize,
|
||||
Uint32& outMipLevelCount) {
|
||||
const auto* mipTexture = dynamic_cast<const MG_State::GLState::TextureObjectMipmap*>(&texture);
|
||||
if (!mipTexture) {
|
||||
MGLOG_D("%s: not TextureObjectMipmap", __func__);
|
||||
return false;
|
||||
}
|
||||
const auto& targets = texture.GetUploadTargets();
|
||||
if (targets.empty()) {
|
||||
MGLOG_D("%s: upload target empty", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto target : targets) {
|
||||
const Uint32 mipLevelCount = GetUploadMipLevelCount(*mipTexture, target);
|
||||
if (mipLevelCount == 0) {
|
||||
MGLOG_D("%s: mipLevelCount == 0", __func__);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto level0TexelSize = mipTexture->GetMipmapTexelSize(target, 0);
|
||||
const auto level0ByteSize = mipTexture->GetMipmapByteSize(target, 0);
|
||||
if (level0TexelSize.x() <= 0 || level0TexelSize.y() <= 0 /*|| level0ByteSize == 0*/) {
|
||||
continue;
|
||||
}
|
||||
|
||||
outTarget = target;
|
||||
outTexelSize = level0TexelSize;
|
||||
outByteSize = level0ByteSize;
|
||||
outMipLevelCount = mipLevelCount;
|
||||
return true;
|
||||
}
|
||||
MGLOG_D("%s: no valid target or mipmap", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
Uint32 VkTextureManager::GetUploadMipLevelCount(const MG_State::GLState::TextureObjectMipmap& texture,
|
||||
TextureUploadTarget target) {
|
||||
const Uint totalLevelCount = texture.GetMipmapLevelCount();
|
||||
if (totalLevelCount == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Uint32 validLevelCount = 0;
|
||||
for (Uint level = 0; level < totalLevelCount; ++level) {
|
||||
const auto size = texture.GetMipmapTexelSize(target, level);
|
||||
const auto byteSize = texture.GetMipmapByteSize(target, level);
|
||||
if (size.x() <= 0 || size.y() <= 0 /*|| byteSize == 0*/) {
|
||||
break;
|
||||
}
|
||||
++validLevelCount;
|
||||
}
|
||||
return validLevelCount;
|
||||
}
|
||||
|
||||
VkImageAspectFlags VkTextureManager::GetAspectMaskForFormat(VkFormat format) {
|
||||
switch (format) {
|
||||
case VK_FORMAT_D16_UNORM:
|
||||
case VK_FORMAT_X8_D24_UNORM_PACK32:
|
||||
case VK_FORMAT_D32_SFLOAT:
|
||||
return VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
case VK_FORMAT_S8_UINT:
|
||||
return VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
case VK_FORMAT_D16_UNORM_S8_UINT:
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
||||
return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
default:
|
||||
return VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
}
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -0,0 +1,122 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../VkIncludes.h"
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/TextureState/TextureObject.h>
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
class ITextureObject;
|
||||
}
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
class VkTextureManager {
|
||||
public:
|
||||
struct InitInfo {
|
||||
VkDevice device = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
||||
VmaAllocator allocator = nullptr;
|
||||
VkCommandPool commandPool = VK_NULL_HANDLE;
|
||||
VkQueue graphicsQueue = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
struct TextureResource {
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
VmaAllocation allocation = nullptr;
|
||||
VkImageView view = VK_NULL_HANDLE;
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VkExtent2D extent = {0, 0};
|
||||
Uint32 mipLevels = 1;
|
||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||
VkImageAspectFlags aspect = VK_IMAGE_ASPECT_NONE;
|
||||
|
||||
TextureResource() = default;
|
||||
TextureResource(const TextureResource&) = delete;
|
||||
TextureResource(TextureResource&& that) noexcept {
|
||||
std::swap(this->image, that.image);
|
||||
std::swap(this->allocation, that.allocation);
|
||||
std::swap(this->view, that.view);
|
||||
std::swap(this->layout, that.layout);
|
||||
std::swap(this->extent, that.extent);
|
||||
std::swap(this->mipLevels, that.mipLevels);
|
||||
std::swap(this->format, that.format);
|
||||
std::swap(this->aspect, that.aspect);
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
if (view != VK_NULL_HANDLE) {
|
||||
vkDestroyImageView(s_device, view, nullptr);
|
||||
}
|
||||
if (image != VK_NULL_HANDLE && allocation != nullptr) {
|
||||
vmaDestroyImage(s_allocator, image, allocation);
|
||||
}
|
||||
view = VK_NULL_HANDLE;
|
||||
image = VK_NULL_HANDLE;
|
||||
allocation = nullptr;
|
||||
layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
extent = {0, 0};
|
||||
mipLevels = 1;
|
||||
format = VK_FORMAT_UNDEFINED;
|
||||
aspect = VK_IMAGE_ASPECT_NONE;
|
||||
}
|
||||
|
||||
~TextureResource() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
static inline VkDevice s_device = VK_NULL_HANDLE;
|
||||
static inline VmaAllocator s_allocator = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
Bool Initialize(const InitInfo& initInfo);
|
||||
void Shutdown();
|
||||
|
||||
TextureResource* SyncTextureAndGetDescriptor(
|
||||
MG_State::GLState::ITextureObject& texture);
|
||||
void UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout);
|
||||
Bool TransitionTextureForSampling(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture);
|
||||
|
||||
static Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout,
|
||||
VkImageLayout newLayout, VkPipelineStageFlags srcStageMask,
|
||||
VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask,
|
||||
VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask);
|
||||
|
||||
SizeT CollectGarbage();
|
||||
private:
|
||||
|
||||
Bool SyncTexture(MG_State::GLState::ITextureObject &texture,
|
||||
TextureResource &outResource);
|
||||
Bool SyncTextureResource(const MG_State::GLState::ITextureObject &texture,
|
||||
TextureUploadTarget uploadTarget,
|
||||
const IntVec3 &texelSize, SizeT byteSize, Uint32 mipLevels,
|
||||
TextureResource &resource);
|
||||
Bool UploadDirtyMipLevels(MG_State::GLState::TextureObjectMipmap &mipmapTexture,
|
||||
TextureUploadTarget uploadTarget,
|
||||
TextureResource &outResource);
|
||||
static Bool CheckMipmapCompleteness(const MG_State::GLState::ITextureObject& texture,
|
||||
TextureUploadTarget& outTarget,
|
||||
IntVec3& outTexelSize,
|
||||
SizeT& outByteSize,
|
||||
Uint32& outMipLevelCount);
|
||||
static Uint32 GetUploadMipLevelCount(const MG_State::GLState::TextureObjectMipmap& texture, TextureUploadTarget target);
|
||||
static VkImageAspectFlags GetAspectMaskForFormat(VkFormat format);
|
||||
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
|
||||
VmaAllocator m_allocator = nullptr;
|
||||
VkCommandPool m_commandPool = VK_NULL_HANDLE;
|
||||
VkQueue m_graphicsQueue = VK_NULL_HANDLE;
|
||||
|
||||
Uint8 m_gcCounter = 0;
|
||||
UnorderedMap<MG_State::GLState::ITextureObject*, WeakPtr<MG_State::GLState::ITextureObject>> m_aliveObjects;
|
||||
UnorderedMap<MG_State::GLState::ITextureObject*, TextureResource> m_textureResources;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -1,644 +0,0 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureSamplerManager.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "VkTextureSamplerManager.h"
|
||||
|
||||
#include "MG_State/GLState/Core.h"
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
namespace {
|
||||
constexpr Uint64 BuildSamplerKey(Uint externalIndex, Uint16 version) {
|
||||
return (static_cast<Uint64>(externalIndex) << 16) | static_cast<Uint64>(version);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Bool VkTextureSamplerManager::Initialize(const InitInfo& initInfo) {
|
||||
Shutdown();
|
||||
|
||||
m_device = initInfo.device;
|
||||
m_physicalDevice = initInfo.physicalDevice;
|
||||
m_commandPool = initInfo.commandPool;
|
||||
m_graphicsQueue = initInfo.graphicsQueue;
|
||||
|
||||
if (m_device == VK_NULL_HANDLE || m_physicalDevice == VK_NULL_HANDLE || m_commandPool == VK_NULL_HANDLE ||
|
||||
m_graphicsQueue == VK_NULL_HANDLE) {
|
||||
MGLOG_E("VkTextureSamplerManager::Initialize failed: invalid Vulkan handles");
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!UploadFallbackTexture()) {
|
||||
MGLOG_E("VkTextureSamplerManager::Initialize failed: fallback texture creation failed");
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void VkTextureSamplerManager::Shutdown() {
|
||||
for (auto& [_, resource] : m_textureResources) {
|
||||
DestroyTextureResource(resource);
|
||||
}
|
||||
m_textureResources.clear();
|
||||
|
||||
for (auto& [_, sampler] : m_samplers) {
|
||||
if (m_device != VK_NULL_HANDLE && sampler.handle != VK_NULL_HANDLE) {
|
||||
vkDestroySampler(m_device, sampler.handle, nullptr);
|
||||
}
|
||||
sampler.handle = VK_NULL_HANDLE;
|
||||
}
|
||||
m_samplers.clear();
|
||||
|
||||
if (m_device != VK_NULL_HANDLE && m_fallbackSampler != VK_NULL_HANDLE) {
|
||||
vkDestroySampler(m_device, m_fallbackSampler, nullptr);
|
||||
}
|
||||
if (m_device != VK_NULL_HANDLE && m_fallbackImageView != VK_NULL_HANDLE) {
|
||||
vkDestroyImageView(m_device, m_fallbackImageView, nullptr);
|
||||
}
|
||||
if (m_device != VK_NULL_HANDLE && m_fallbackImage != VK_NULL_HANDLE) {
|
||||
vkDestroyImage(m_device, m_fallbackImage, nullptr);
|
||||
}
|
||||
if (m_device != VK_NULL_HANDLE && m_fallbackImageMemory != VK_NULL_HANDLE) {
|
||||
vkFreeMemory(m_device, m_fallbackImageMemory, nullptr);
|
||||
}
|
||||
m_fallbackSampler = VK_NULL_HANDLE;
|
||||
m_fallbackImageView = VK_NULL_HANDLE;
|
||||
m_fallbackImage = VK_NULL_HANDLE;
|
||||
m_fallbackImageMemory = VK_NULL_HANDLE;
|
||||
|
||||
m_device = VK_NULL_HANDLE;
|
||||
m_physicalDevice = VK_NULL_HANDLE;
|
||||
m_commandPool = VK_NULL_HANDLE;
|
||||
m_graphicsQueue = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
Bool VkTextureSamplerManager::GetFallbackDescriptor(VkDescriptorImageInfo& outImageInfo) const {
|
||||
if (m_fallbackSampler == VK_NULL_HANDLE || m_fallbackImageView == VK_NULL_HANDLE) {
|
||||
return false;
|
||||
}
|
||||
outImageInfo.sampler = m_fallbackSampler;
|
||||
outImageInfo.imageView = m_fallbackImageView;
|
||||
outImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkTextureSamplerManager::SyncTextureAndGetDescriptor(const MG_State::GLState::ITextureObject& texture,
|
||||
const MG_State::GLState::SamplerObject* samplerOverride,
|
||||
VkDescriptorImageInfo& outImageInfo) {
|
||||
if (m_device == VK_NULL_HANDLE) {
|
||||
return GetFallbackDescriptor(outImageInfo);
|
||||
}
|
||||
|
||||
auto it = m_textureResources.find(texture.GetExternalIndex());
|
||||
if (it == m_textureResources.end()) {
|
||||
TextureResource initial{};
|
||||
initial.textureExternalIndex = texture.GetExternalIndex();
|
||||
auto [insertIt, _] = m_textureResources.emplace(texture.GetExternalIndex(), initial);
|
||||
it = insertIt;
|
||||
}
|
||||
|
||||
if (!EnsureTextureSynced(it->second, texture)) {
|
||||
return GetFallbackDescriptor(outImageInfo);
|
||||
}
|
||||
|
||||
const MG_State::GLState::SamplerObject* samplerToUse = samplerOverride;
|
||||
if (!samplerToUse) {
|
||||
auto textureSampler = texture.GetSamplerObject();
|
||||
if (textureSampler) {
|
||||
samplerToUse = textureSampler.get();
|
||||
}
|
||||
}
|
||||
|
||||
VkSampler sampler = m_fallbackSampler;
|
||||
if (samplerToUse) {
|
||||
sampler = GetOrCreateSampler(*samplerToUse);
|
||||
}
|
||||
if (sampler == VK_NULL_HANDLE) {
|
||||
sampler = m_fallbackSampler;
|
||||
}
|
||||
|
||||
if (it->second.view == VK_NULL_HANDLE || sampler == VK_NULL_HANDLE) {
|
||||
return GetFallbackDescriptor(outImageInfo);
|
||||
}
|
||||
|
||||
outImageInfo.sampler = sampler;
|
||||
outImageInfo.imageView = it->second.view;
|
||||
outImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkTextureSamplerManager::EnsureTextureSynced(TextureResource& resource,
|
||||
const MG_State::GLState::ITextureObject& texture) {
|
||||
TextureUploadTarget level0Target = TextureUploadTarget::Unknown;
|
||||
IntVec3 texelSize{0, 0, 0};
|
||||
SizeT byteSize = 0;
|
||||
if (!ResolveLevel0(texture, level0Target, texelSize, byteSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!EnsureTextureResource(resource, texture, level0Target, texelSize, byteSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto* mipTexture = dynamic_cast<const MG_State::GLState::TextureObjectMipmap*>(&texture);
|
||||
if (!mipTexture) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mipTexture->IsStorageDirty(level0Target, 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!UploadLevel0(resource, *mipTexture, level0Target, byteSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& mutableTexture = const_cast<MG_State::GLState::TextureObjectMipmap&>(*mipTexture);
|
||||
mutableTexture.MarkStorageDirty(level0Target, 0, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkTextureSamplerManager::EnsureTextureResource(TextureResource& resource,
|
||||
const MG_State::GLState::ITextureObject& texture,
|
||||
TextureUploadTarget level0Target, const IntVec3& texelSize,
|
||||
SizeT byteSize) {
|
||||
const VkFormat format = ResolveTextureFormat(texture.GetFormat());
|
||||
if (format == VK_FORMAT_UNDEFINED) {
|
||||
return false;
|
||||
}
|
||||
if (texelSize.x() <= 0 || texelSize.y() <= 0 || byteSize == 0) {
|
||||
return false;
|
||||
}
|
||||
if (level0Target != TextureUploadTarget::Texture2D) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Bool compatible = resource.image != VK_NULL_HANDLE && resource.format == format &&
|
||||
resource.extent.width == static_cast<Uint32>(texelSize.x()) &&
|
||||
resource.extent.height == static_cast<Uint32>(texelSize.y());
|
||||
if (compatible) {
|
||||
return true;
|
||||
}
|
||||
|
||||
DestroyTextureResource(resource);
|
||||
|
||||
VkImageCreateInfo imageInfo{};
|
||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.extent.width = static_cast<Uint32>(texelSize.x());
|
||||
imageInfo.extent.height = static_cast<Uint32>(texelSize.y());
|
||||
imageInfo.extent.depth = 1;
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.arrayLayers = 1;
|
||||
imageInfo.format = format;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VK_VERIFY(vkCreateImage(m_device, &imageInfo, nullptr, &resource.image), "vkCreateImage(texture)");
|
||||
|
||||
VkMemoryRequirements requirements{};
|
||||
vkGetImageMemoryRequirements(m_device, resource.image, &requirements);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = requirements.size;
|
||||
allocInfo.memoryTypeIndex = FindMemoryType(requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
VK_VERIFY(vkAllocateMemory(m_device, &allocInfo, nullptr, &resource.memory), "vkAllocateMemory(texture)");
|
||||
VK_VERIFY(vkBindImageMemory(m_device, resource.image, resource.memory, 0), "vkBindImageMemory(texture)");
|
||||
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = resource.image;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = format;
|
||||
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.subresourceRange.baseMipLevel = 0;
|
||||
viewInfo.subresourceRange.levelCount = 1;
|
||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
viewInfo.subresourceRange.layerCount = 1;
|
||||
VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &resource.view), "vkCreateImageView(texture)");
|
||||
|
||||
resource.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
resource.extent = {static_cast<Uint32>(texelSize.x()), static_cast<Uint32>(texelSize.y())};
|
||||
resource.format = format;
|
||||
resource.textureExternalIndex = texture.GetExternalIndex();
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkTextureSamplerManager::UploadLevel0(TextureResource& resource,
|
||||
const MG_State::GLState::TextureObjectMipmap& mipmapTexture,
|
||||
TextureUploadTarget level0Target, SizeT byteSize) {
|
||||
auto& mutableTexture = const_cast<MG_State::GLState::TextureObjectMipmap&>(mipmapTexture);
|
||||
const void* source = mutableTexture.MapMipmapData(level0Target, 0);
|
||||
if (source == nullptr || byteSize == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VkBuffer stagingBuffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory stagingMemory = VK_NULL_HANDLE;
|
||||
|
||||
VkBufferCreateInfo bufferInfo{};
|
||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
bufferInfo.size = byteSize;
|
||||
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VK_VERIFY(vkCreateBuffer(m_device, &bufferInfo, nullptr, &stagingBuffer), "vkCreateBuffer(staging texture)");
|
||||
|
||||
VkMemoryRequirements requirements{};
|
||||
vkGetBufferMemoryRequirements(m_device, stagingBuffer, &requirements);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = requirements.size;
|
||||
allocInfo.memoryTypeIndex =
|
||||
FindMemoryType(requirements.memoryTypeBits,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
VK_VERIFY(vkAllocateMemory(m_device, &allocInfo, nullptr, &stagingMemory), "vkAllocateMemory(staging texture)");
|
||||
VK_VERIFY(vkBindBufferMemory(m_device, stagingBuffer, stagingMemory, 0), "vkBindBufferMemory(staging texture)");
|
||||
|
||||
void* mapped = nullptr;
|
||||
VK_VERIFY(vkMapMemory(m_device, stagingMemory, 0, byteSize, 0, &mapped), "vkMapMemory(staging texture)");
|
||||
std::memcpy(mapped, source, byteSize);
|
||||
vkUnmapMemory(m_device, stagingMemory);
|
||||
|
||||
const Bool ok = ExecuteImmediate([&](VkCommandBuffer commandBuffer) {
|
||||
VkImageMemoryBarrier toTransferDst{};
|
||||
toTransferDst.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
toTransferDst.srcAccessMask = 0;
|
||||
toTransferDst.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
toTransferDst.oldLayout = resource.layout;
|
||||
toTransferDst.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
toTransferDst.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
toTransferDst.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
toTransferDst.image = resource.image;
|
||||
toTransferDst.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
toTransferDst.subresourceRange.baseMipLevel = 0;
|
||||
toTransferDst.subresourceRange.levelCount = 1;
|
||||
toTransferDst.subresourceRange.baseArrayLayer = 0;
|
||||
toTransferDst.subresourceRange.layerCount = 1;
|
||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0,
|
||||
nullptr, 0, nullptr, 1, &toTransferDst);
|
||||
|
||||
VkBufferImageCopy copy{};
|
||||
copy.bufferOffset = 0;
|
||||
copy.bufferRowLength = 0;
|
||||
copy.bufferImageHeight = 0;
|
||||
copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
copy.imageSubresource.mipLevel = 0;
|
||||
copy.imageSubresource.baseArrayLayer = 0;
|
||||
copy.imageSubresource.layerCount = 1;
|
||||
copy.imageOffset = {0, 0, 0};
|
||||
copy.imageExtent = {resource.extent.width, resource.extent.height, 1};
|
||||
vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, resource.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
|
||||
©);
|
||||
|
||||
VkImageMemoryBarrier toSampled{};
|
||||
toSampled.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
toSampled.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
toSampled.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
toSampled.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
toSampled.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
toSampled.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
toSampled.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
toSampled.image = resource.image;
|
||||
toSampled.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
toSampled.subresourceRange.baseMipLevel = 0;
|
||||
toSampled.subresourceRange.levelCount = 1;
|
||||
toSampled.subresourceRange.baseArrayLayer = 0;
|
||||
toSampled.subresourceRange.layerCount = 1;
|
||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
|
||||
0, nullptr, 0, nullptr, 1, &toSampled);
|
||||
});
|
||||
|
||||
vkDestroyBuffer(m_device, stagingBuffer, nullptr);
|
||||
vkFreeMemory(m_device, stagingMemory, nullptr);
|
||||
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
resource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkTextureSamplerManager::ExecuteImmediate(const std::function<void(VkCommandBuffer)>& recorder) const {
|
||||
VkCommandBufferAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocInfo.commandPool = m_commandPool;
|
||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
allocInfo.commandBufferCount = 1;
|
||||
|
||||
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
|
||||
VK_VERIFY(vkAllocateCommandBuffers(m_device, &allocInfo, &commandBuffer), "vkAllocateCommandBuffers(texture)");
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo{};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
VK_VERIFY(vkBeginCommandBuffer(commandBuffer, &beginInfo), "vkBeginCommandBuffer(texture)");
|
||||
|
||||
recorder(commandBuffer);
|
||||
|
||||
VK_VERIFY(vkEndCommandBuffer(commandBuffer), "vkEndCommandBuffer(texture)");
|
||||
|
||||
VkSubmitInfo submitInfo{};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &commandBuffer;
|
||||
VK_VERIFY(vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE), "vkQueueSubmit(texture)");
|
||||
VK_VERIFY(vkQueueWaitIdle(m_graphicsQueue), "vkQueueWaitIdle(texture)");
|
||||
|
||||
vkFreeCommandBuffers(m_device, m_commandPool, 1, &commandBuffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VkTextureSamplerManager::DestroyTextureResource(TextureResource& resource) const {
|
||||
if (m_device != VK_NULL_HANDLE && resource.view != VK_NULL_HANDLE) {
|
||||
vkDestroyImageView(m_device, resource.view, nullptr);
|
||||
}
|
||||
if (m_device != VK_NULL_HANDLE && resource.image != VK_NULL_HANDLE) {
|
||||
vkDestroyImage(m_device, resource.image, nullptr);
|
||||
}
|
||||
if (m_device != VK_NULL_HANDLE && resource.memory != VK_NULL_HANDLE) {
|
||||
vkFreeMemory(m_device, resource.memory, nullptr);
|
||||
}
|
||||
resource.view = VK_NULL_HANDLE;
|
||||
resource.image = VK_NULL_HANDLE;
|
||||
resource.memory = VK_NULL_HANDLE;
|
||||
resource.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
resource.extent = {0, 0};
|
||||
resource.format = VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
|
||||
Bool VkTextureSamplerManager::ResolveLevel0(const MG_State::GLState::ITextureObject& texture,
|
||||
TextureUploadTarget& outTarget, IntVec3& outTexelSize,
|
||||
SizeT& outByteSize) {
|
||||
const auto* mipTexture = dynamic_cast<const MG_State::GLState::TextureObjectMipmap*>(&texture);
|
||||
if (!mipTexture) {
|
||||
return false;
|
||||
}
|
||||
const auto& targets = texture.GetUploadTargets();
|
||||
if (targets.empty()) {
|
||||
return false;
|
||||
}
|
||||
outTarget = targets.front();
|
||||
outTexelSize = mipTexture->GetMipmapTexelSize(outTarget, 0);
|
||||
outByteSize = mipTexture->GetMipmapByteSize(outTarget, 0);
|
||||
return outTexelSize.x() > 0 && outTexelSize.y() > 0 && outByteSize > 0;
|
||||
}
|
||||
|
||||
VkFormat VkTextureSamplerManager::ResolveTextureFormat(TextureInternalFormat format) {
|
||||
switch (format) {
|
||||
case TextureInternalFormat::RGBA:
|
||||
case TextureInternalFormat::RGBA8:
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
case TextureInternalFormat::SRGB8Alpha8:
|
||||
return VK_FORMAT_R8G8B8A8_SRGB;
|
||||
default:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
Uint32 VkTextureSamplerManager::FindMemoryType(Uint32 typeFilter, VkMemoryPropertyFlags properties) const {
|
||||
VkPhysicalDeviceMemoryProperties memProperties{};
|
||||
vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &memProperties);
|
||||
for (Uint32 i = 0; i < memProperties.memoryTypeCount; ++i) {
|
||||
if ((typeFilter & (1u << i)) != 0 &&
|
||||
(memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
MOBILEGL_ASSERT(false, "VkTextureSamplerManager::FindMemoryType failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
VkSampler VkTextureSamplerManager::GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler) {
|
||||
const Uint64 key = BuildSamplerKey(sampler.GetExternalIndex(), sampler.GetVersion());
|
||||
auto it = m_samplers.find(key);
|
||||
if (it != m_samplers.end()) {
|
||||
return it->second.handle;
|
||||
}
|
||||
|
||||
VkSamplerCreateInfo samplerInfo{};
|
||||
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||
samplerInfo.magFilter = ToVkFilter(sampler.GetMagFilter());
|
||||
samplerInfo.minFilter = ToVkFilter(sampler.GetMinFilter());
|
||||
samplerInfo.mipmapMode = ToVkMipmapMode(sampler.GetMipmapMode());
|
||||
samplerInfo.addressModeU = ToVkAddressMode(sampler.GetWrapS());
|
||||
samplerInfo.addressModeV = ToVkAddressMode(sampler.GetWrapT());
|
||||
samplerInfo.addressModeW = ToVkAddressMode(sampler.GetWrapR());
|
||||
samplerInfo.mipLodBias = sampler.GetLodBias();
|
||||
samplerInfo.anisotropyEnable = VK_FALSE;
|
||||
samplerInfo.maxAnisotropy = 1.0f;
|
||||
samplerInfo.compareEnable = sampler.GetCompareMode() == SamplerCompareMode::CompareToTexture ? VK_TRUE : VK_FALSE;
|
||||
samplerInfo.compareOp = ToVkCompareOp(sampler.GetSamplerCompareFunc());
|
||||
samplerInfo.minLod = sampler.GetMinLod();
|
||||
samplerInfo.maxLod = sampler.GetMaxLod();
|
||||
samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
||||
samplerInfo.unnormalizedCoordinates = VK_FALSE;
|
||||
|
||||
VkSampler vkSampler = VK_NULL_HANDLE;
|
||||
VK_VERIFY(vkCreateSampler(m_device, &samplerInfo, nullptr, &vkSampler), "vkCreateSampler(texture)");
|
||||
|
||||
SamplerCacheEntry entry{};
|
||||
entry.handle = vkSampler;
|
||||
entry.externalIndex = sampler.GetExternalIndex();
|
||||
entry.version = sampler.GetVersion();
|
||||
m_samplers[key] = entry;
|
||||
return vkSampler;
|
||||
}
|
||||
|
||||
VkFilter VkTextureSamplerManager::ToVkFilter(SamplerFilterMode mode) {
|
||||
return mode == SamplerFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;
|
||||
}
|
||||
|
||||
VkSamplerMipmapMode VkTextureSamplerManager::ToVkMipmapMode(SamplerMipmapMode mode) {
|
||||
switch (mode) {
|
||||
case SamplerMipmapMode::Nearest:
|
||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
case SamplerMipmapMode::Linear:
|
||||
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
case SamplerMipmapMode::None:
|
||||
default:
|
||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
}
|
||||
}
|
||||
|
||||
VkSamplerAddressMode VkTextureSamplerManager::ToVkAddressMode(SamplerWrapMode mode) {
|
||||
switch (mode) {
|
||||
case SamplerWrapMode::ClampToEdge:
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
case SamplerWrapMode::MirroredRepeat:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
||||
case SamplerWrapMode::Repeat:
|
||||
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
case SamplerWrapMode::ClampToBorder:
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||
case SamplerWrapMode::MirrorClampToEdge:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
|
||||
default:
|
||||
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
}
|
||||
}
|
||||
|
||||
VkCompareOp VkTextureSamplerManager::ToVkCompareOp(SamplerCompareFunc func) {
|
||||
switch (func) {
|
||||
case SamplerCompareFunc::Never:
|
||||
return VK_COMPARE_OP_NEVER;
|
||||
case SamplerCompareFunc::Less:
|
||||
return VK_COMPARE_OP_LESS;
|
||||
case SamplerCompareFunc::Equal:
|
||||
return VK_COMPARE_OP_EQUAL;
|
||||
case SamplerCompareFunc::LessEqual:
|
||||
return VK_COMPARE_OP_LESS_OR_EQUAL;
|
||||
case SamplerCompareFunc::Greater:
|
||||
return VK_COMPARE_OP_GREATER;
|
||||
case SamplerCompareFunc::NotEqual:
|
||||
return VK_COMPARE_OP_NOT_EQUAL;
|
||||
case SamplerCompareFunc::GreaterEqual:
|
||||
return VK_COMPARE_OP_GREATER_OR_EQUAL;
|
||||
case SamplerCompareFunc::Always:
|
||||
default:
|
||||
return VK_COMPARE_OP_ALWAYS;
|
||||
}
|
||||
}
|
||||
|
||||
Bool VkTextureSamplerManager::UploadFallbackTexture() {
|
||||
const Uint32 rgba = 0xFFFFFFFFu;
|
||||
|
||||
VkImageCreateInfo imageInfo{};
|
||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.extent = {1, 1, 1};
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.arrayLayers = 1;
|
||||
imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VK_VERIFY(vkCreateImage(m_device, &imageInfo, nullptr, &m_fallbackImage), "vkCreateImage(fallback)");
|
||||
|
||||
VkMemoryRequirements imageMemReq{};
|
||||
vkGetImageMemoryRequirements(m_device, m_fallbackImage, &imageMemReq);
|
||||
|
||||
VkMemoryAllocateInfo imageAllocInfo{};
|
||||
imageAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
imageAllocInfo.allocationSize = imageMemReq.size;
|
||||
imageAllocInfo.memoryTypeIndex = FindMemoryType(imageMemReq.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
VK_VERIFY(vkAllocateMemory(m_device, &imageAllocInfo, nullptr, &m_fallbackImageMemory),
|
||||
"vkAllocateMemory(fallback)");
|
||||
VK_VERIFY(vkBindImageMemory(m_device, m_fallbackImage, m_fallbackImageMemory, 0), "vkBindImageMemory(fallback)");
|
||||
|
||||
VkBuffer stagingBuffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory stagingMemory = VK_NULL_HANDLE;
|
||||
|
||||
VkBufferCreateInfo bufferInfo{};
|
||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
bufferInfo.size = sizeof(rgba);
|
||||
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VK_VERIFY(vkCreateBuffer(m_device, &bufferInfo, nullptr, &stagingBuffer), "vkCreateBuffer(fallback)");
|
||||
|
||||
VkMemoryRequirements stagingMemReq{};
|
||||
vkGetBufferMemoryRequirements(m_device, stagingBuffer, &stagingMemReq);
|
||||
|
||||
VkMemoryAllocateInfo stagingAllocInfo{};
|
||||
stagingAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
stagingAllocInfo.allocationSize = stagingMemReq.size;
|
||||
stagingAllocInfo.memoryTypeIndex =
|
||||
FindMemoryType(stagingMemReq.memoryTypeBits,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
VK_VERIFY(vkAllocateMemory(m_device, &stagingAllocInfo, nullptr, &stagingMemory), "vkAllocateMemory(fallback)");
|
||||
VK_VERIFY(vkBindBufferMemory(m_device, stagingBuffer, stagingMemory, 0), "vkBindBufferMemory(fallback)");
|
||||
|
||||
void* mapped = nullptr;
|
||||
VK_VERIFY(vkMapMemory(m_device, stagingMemory, 0, sizeof(rgba), 0, &mapped), "vkMapMemory(fallback)");
|
||||
std::memcpy(mapped, &rgba, sizeof(rgba));
|
||||
vkUnmapMemory(m_device, stagingMemory);
|
||||
|
||||
const Bool uploadOk = ExecuteImmediate([&](VkCommandBuffer commandBuffer) {
|
||||
VkImageMemoryBarrier toTransferDst{};
|
||||
toTransferDst.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
toTransferDst.srcAccessMask = 0;
|
||||
toTransferDst.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
toTransferDst.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
toTransferDst.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
toTransferDst.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
toTransferDst.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
toTransferDst.image = m_fallbackImage;
|
||||
toTransferDst.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
toTransferDst.subresourceRange.baseMipLevel = 0;
|
||||
toTransferDst.subresourceRange.levelCount = 1;
|
||||
toTransferDst.subresourceRange.baseArrayLayer = 0;
|
||||
toTransferDst.subresourceRange.layerCount = 1;
|
||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0,
|
||||
nullptr, 0, nullptr, 1, &toTransferDst);
|
||||
|
||||
VkBufferImageCopy copy{};
|
||||
copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
copy.imageSubresource.mipLevel = 0;
|
||||
copy.imageSubresource.baseArrayLayer = 0;
|
||||
copy.imageSubresource.layerCount = 1;
|
||||
copy.imageExtent = {1, 1, 1};
|
||||
vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, m_fallbackImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
|
||||
©);
|
||||
|
||||
VkImageMemoryBarrier toSampled{};
|
||||
toSampled.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
toSampled.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
toSampled.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
toSampled.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
toSampled.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
toSampled.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
toSampled.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
toSampled.image = m_fallbackImage;
|
||||
toSampled.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
toSampled.subresourceRange.baseMipLevel = 0;
|
||||
toSampled.subresourceRange.levelCount = 1;
|
||||
toSampled.subresourceRange.baseArrayLayer = 0;
|
||||
toSampled.subresourceRange.layerCount = 1;
|
||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
|
||||
0, nullptr, 0, nullptr, 1, &toSampled);
|
||||
});
|
||||
|
||||
vkDestroyBuffer(m_device, stagingBuffer, nullptr);
|
||||
vkFreeMemory(m_device, stagingMemory, nullptr);
|
||||
if (!uploadOk) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = m_fallbackImage;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.subresourceRange.baseMipLevel = 0;
|
||||
viewInfo.subresourceRange.levelCount = 1;
|
||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
viewInfo.subresourceRange.layerCount = 1;
|
||||
VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &m_fallbackImageView), "vkCreateImageView(fallback)");
|
||||
|
||||
VkSamplerCreateInfo samplerInfo{};
|
||||
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||
samplerInfo.magFilter = VK_FILTER_NEAREST;
|
||||
samplerInfo.minFilter = VK_FILTER_NEAREST;
|
||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.compareEnable = VK_FALSE;
|
||||
samplerInfo.minLod = 0.0f;
|
||||
samplerInfo.maxLod = 0.0f;
|
||||
samplerInfo.maxAnisotropy = 1.0f;
|
||||
VK_VERIFY(vkCreateSampler(m_device, &samplerInfo, nullptr, &m_fallbackSampler), "vkCreateSampler(fallback)");
|
||||
return true;
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureSamplerManager.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../VkIncludes.h"
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/SamplerState/SamplerObject.h>
|
||||
#include <MG_State/GLState/TextureState/TextureObject.h>
|
||||
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
class ITextureObject;
|
||||
class SamplerObject;
|
||||
}
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
class VkTextureSamplerManager {
|
||||
public:
|
||||
struct InitInfo {
|
||||
VkDevice device = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
||||
VkCommandPool commandPool = VK_NULL_HANDLE;
|
||||
VkQueue graphicsQueue = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
Bool Initialize(const InitInfo& initInfo);
|
||||
void Shutdown();
|
||||
|
||||
Bool GetFallbackDescriptor(VkDescriptorImageInfo& outImageInfo) const;
|
||||
Bool SyncTextureAndGetDescriptor(const MG_State::GLState::ITextureObject& texture,
|
||||
const MG_State::GLState::SamplerObject* samplerOverride,
|
||||
VkDescriptorImageInfo& outImageInfo);
|
||||
|
||||
private:
|
||||
struct TextureResource {
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
||||
VkImageView view = VK_NULL_HANDLE;
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
VkExtent2D extent = {0, 0};
|
||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||
Uint textureExternalIndex = 0;
|
||||
};
|
||||
|
||||
struct SamplerCacheEntry {
|
||||
VkSampler handle = VK_NULL_HANDLE;
|
||||
Uint externalIndex = 0;
|
||||
Uint16 version = 0;
|
||||
};
|
||||
|
||||
Bool EnsureTextureSynced(TextureResource& resource, const MG_State::GLState::ITextureObject& texture);
|
||||
Bool EnsureTextureResource(TextureResource& resource, const MG_State::GLState::ITextureObject& texture,
|
||||
TextureUploadTarget level0Target, const IntVec3& texelSize, SizeT byteSize);
|
||||
Bool UploadLevel0(TextureResource& resource, const MG_State::GLState::TextureObjectMipmap& mipmapTexture,
|
||||
TextureUploadTarget level0Target, SizeT byteSize);
|
||||
Bool ExecuteImmediate(const std::function<void(VkCommandBuffer)>& recorder) const;
|
||||
void DestroyTextureResource(TextureResource& resource) const;
|
||||
static Bool ResolveLevel0(const MG_State::GLState::ITextureObject& texture, TextureUploadTarget& outTarget,
|
||||
IntVec3& outTexelSize, SizeT& outByteSize);
|
||||
static VkFormat ResolveTextureFormat(TextureInternalFormat format);
|
||||
Uint32 FindMemoryType(Uint32 typeFilter, VkMemoryPropertyFlags properties) const;
|
||||
|
||||
VkSampler GetOrCreateSampler(const MG_State::GLState::SamplerObject& sampler);
|
||||
static VkFilter ToVkFilter(SamplerFilterMode mode);
|
||||
static VkSamplerMipmapMode ToVkMipmapMode(SamplerMipmapMode mode);
|
||||
static VkSamplerAddressMode ToVkAddressMode(SamplerWrapMode mode);
|
||||
static VkCompareOp ToVkCompareOp(SamplerCompareFunc func);
|
||||
Bool UploadFallbackTexture();
|
||||
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
|
||||
VkCommandPool m_commandPool = VK_NULL_HANDLE;
|
||||
VkQueue m_graphicsQueue = VK_NULL_HANDLE;
|
||||
|
||||
UnorderedMap<Uint, TextureResource> m_textureResources;
|
||||
UnorderedMap<Uint64, SamplerCacheEntry> m_samplers;
|
||||
|
||||
VkImage m_fallbackImage = VK_NULL_HANDLE;
|
||||
VkDeviceMemory m_fallbackImageMemory = VK_NULL_HANDLE;
|
||||
VkImageView m_fallbackImageView = VK_NULL_HANDLE;
|
||||
VkSampler m_fallbackSampler = VK_NULL_HANDLE;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,9 +15,10 @@
|
||||
#include "UniformDescriptorBinder.h"
|
||||
#include "VertexInputStateFactory.h"
|
||||
#include "VkBufferObject.h"
|
||||
#include "VkFramebufferManager.h"
|
||||
#include "VkClearManager.h"
|
||||
#include "VkRenderPassManager.h"
|
||||
#include "VkTextureSamplerManager.h"
|
||||
#include "VkSamplerManager.h"
|
||||
#include "VkTextureManager.h"
|
||||
#include "MG_Util/Math/VectorTypes.h"
|
||||
#include <Includes.h>
|
||||
#include <vk_mem_alloc.h>
|
||||
@@ -27,20 +28,28 @@
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
class FramebufferObject;
|
||||
class ProgramObject;
|
||||
class SamplerObject;
|
||||
class VertexArrayObject;
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
struct DrawArrayPayload {
|
||||
enum class DrawSetupAspect: Uint8 {
|
||||
FramebufferObject = 1 << 0,
|
||||
VertexArrayObject = 1 << 1,
|
||||
UniformBuffer = 1 << 2,
|
||||
VertexBuffer = 1 << 3,
|
||||
IndexBuffer = 1 << 4,
|
||||
Viewport = 1 << 5,
|
||||
Scissor = 1 << 6,
|
||||
};
|
||||
|
||||
struct DrawArrayCmd {
|
||||
GLenum mode = GL_TRIANGLES;
|
||||
GLint first = 0;
|
||||
GLsizei count = 0;
|
||||
const MG_State::GLState::ProgramObject* program = nullptr;
|
||||
const MG_State::GLState::VertexArrayObject* vertexArray = nullptr;
|
||||
};
|
||||
|
||||
struct DrawElementPayload {
|
||||
DrawArrayPayload drawArray;
|
||||
struct DrawElementCmd: public DrawArrayCmd {
|
||||
GLenum indexType = GL_UNSIGNED_SHORT;
|
||||
SizeT indexByteOffset = 0;
|
||||
GLint baseVertex = 0;
|
||||
@@ -69,17 +78,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
void RequestClear(GLbitfield mask, const FloatVec4& color, Float depth, Uint32 stencil,
|
||||
Uint drawFboExternalIndex, Bool isDefaultFramebufferTarget);
|
||||
Bool ConsumePendingColorClear(VkClearColorValue& outClearColor);
|
||||
void EnsureFrameRecordingStarted();
|
||||
void DrawArrays(const DrawArrayPayload& payload);
|
||||
void DrawElements(const DrawElementPayload& payload);
|
||||
void MultiDrawElements(const Vector<DrawElementPayload>& payloads);
|
||||
Bool BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
||||
GLint dstY1, GLbitfield mask, GLenum filter, Uint readFboExternalIndex,
|
||||
Uint drawFboExternalIndex, Bool readIsDefaultFramebuffer, Bool drawIsDefaultFramebuffer);
|
||||
void Render();
|
||||
void SetupDraw(FrameContext::FrameData& frame, GLenum mode, Flags<DrawSetupAspect> aspects);
|
||||
void ClearAttachmentsOnActiveRenderPass(VkCommandBuffer commandBuffer,
|
||||
const RenderPassEntry& compatibleRenderPassEntry);
|
||||
|
||||
void Clear(GLbitfield mask);
|
||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
||||
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||
GLbitfield mask, GLenum filter);
|
||||
void DrawArrays(const DrawArrayCmd& payload);
|
||||
void DrawElements(const DrawElementCmd& payload);
|
||||
void MultiDrawElements(const Vector<DrawElementCmd>& payloads);
|
||||
void Present();
|
||||
|
||||
const PhysicalDevice& GetPhysicalDevice() const;
|
||||
@@ -88,13 +97,21 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void RecreateSwapchain();
|
||||
|
||||
private:
|
||||
struct PendingClearState {
|
||||
GLbitfield mask = 0;
|
||||
VkClearColorValue color = {{0.0f, 0.0f, 0.0f, 1.0f}};
|
||||
Float depth = 1.0f;
|
||||
Uint32 stencil = 0;
|
||||
Uint drawFboExternalIndex = 0;
|
||||
Bool targetsDefaultFramebuffer = true;
|
||||
struct BlitUniformData {
|
||||
float srcRect[4] = {0.f, 0.f, 1.f, 1.f};
|
||||
float dstRect[4] = {0.f, 0.f, 1.f, 1.f};
|
||||
Int surfaceTransform = 0;
|
||||
Int padding[3] = {0, 0, 0};
|
||||
};
|
||||
|
||||
struct BlitResources {
|
||||
SharedPtr<MG_State::GLState::ProgramObject> program;
|
||||
SharedPtr<MG_State::GLState::SamplerObject> nearestSampler;
|
||||
SharedPtr<MG_State::GLState::SamplerObject> linearSampler;
|
||||
Int srcRectLocation = -1;
|
||||
Int dstRectLocation = -1;
|
||||
Int surfaceTransformLocation = -1;
|
||||
Uint32 samplerBinding = 0;
|
||||
};
|
||||
|
||||
NativeWindowType m_window = 0;
|
||||
@@ -106,15 +123,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkInstance m_instance = VK_NULL_HANDLE;
|
||||
VkDebugUtilsMessengerEXT m_debugMessenger = VK_NULL_HANDLE;
|
||||
PhysicalDevice m_physicalDevice;
|
||||
// VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
VmaAllocator m_allocator = nullptr;
|
||||
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
|
||||
SwapchainObject m_swapchainObject;
|
||||
|
||||
// Vector<VkQueueFamilyProperties> m_queueFamilies;
|
||||
// QueueFamilyIndices m_queueFamilyIndices;
|
||||
|
||||
VkQueue m_graphicsQueue = VK_NULL_HANDLE;
|
||||
VkQueue m_presentQueue = VK_NULL_HANDLE;
|
||||
Bool m_drawIndirectCountExtensionEnabled = false;
|
||||
@@ -126,13 +139,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
VkCommandPool m_commandPool = VK_NULL_HANDLE;
|
||||
|
||||
VkFormat m_depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
Vector<VkImage> m_depthStencilImages;
|
||||
Vector<VkDeviceMemory> m_depthStencilImageMemories;
|
||||
Vector<VkImageView> m_depthStencilImageViews;
|
||||
Vector<VkImageLayout> m_depthStencilImageLayouts;
|
||||
|
||||
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
|
||||
Vector<VkBufferObject> m_frameVertexUploadBuffers;
|
||||
Vector<VkDeviceSize> m_frameVertexUploadHeads;
|
||||
Vector<VkBufferObject> m_frameIndexUploadBuffers;
|
||||
@@ -141,21 +147,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
Uint m_imageIndexAcquired = 0;
|
||||
FrameContext m_frameContext;
|
||||
UnorderedMap<Uint64, PendingClearState> m_pendingClears;
|
||||
Bool m_isMainRenderPassActive = false;
|
||||
VkRenderPass m_activeRenderPass = VK_NULL_HANDLE;
|
||||
VkExtent2D m_activeRenderExtent = {0, 0};
|
||||
VkFormat m_activeDepthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
Bool m_activeRenderTargetIsDefault = true;
|
||||
Uint m_activeDrawFboExternalIndex = 0;
|
||||
|
||||
UniquePtr<PipelineFactory> m_pipelineFactory;
|
||||
UniquePtr<ProgramFactory> m_programFactory;
|
||||
UniquePtr<UniformDescriptorBinder> m_uniformDescriptorBinder;
|
||||
UniquePtr<VertexInputStateFactory> m_vertexInputStateFactory;
|
||||
UniquePtr<VkFramebufferManager> m_framebufferManager;
|
||||
UniquePtr<VkClearManager> m_clearManager;
|
||||
UniquePtr<VkRenderPassManager> m_renderPassManager;
|
||||
UniquePtr<VkTextureSamplerManager> m_textureSamplerManager;
|
||||
UniquePtr<VkTextureManager> m_textureManager;
|
||||
UniquePtr<VkSamplerManager> m_samplerManager;
|
||||
BlitResources m_blitResources;
|
||||
|
||||
void CreateInstance();
|
||||
VkResult SetupDebugMessenger();
|
||||
@@ -169,30 +170,33 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void CreateSwapchain();
|
||||
void CreateCommandPool();
|
||||
void CreateFrameContexts();
|
||||
void CreateDepthStencilResources();
|
||||
void DestroyDepthStencilResources();
|
||||
VkRenderPass GetDefaultLoadRenderPass() const;
|
||||
Bool GetDefaultRenderTargetForCurrentImage(VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer,
|
||||
VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) const;
|
||||
Bool EnsureOffscreenRenderTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo,
|
||||
VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer,
|
||||
VkExtent2D& outExtent, VkFormat& outDepthStencilFormat);
|
||||
void PrepareDemoPipeline();
|
||||
VkPipeline GetOrCreatePipeline(const MG_State::GLState::ProgramObject& program, VkPipelineLayout pipelineLayout,
|
||||
Uint64 vertexInputHash,
|
||||
const VkPipelineVertexInputStateCreateInfo& vertexInputState);
|
||||
void TransitionSwapchainImageToColorAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex);
|
||||
void TransitionDepthStencilImageToAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex);
|
||||
void EndFrameRecordingIfNeeded();
|
||||
|
||||
VkPipeline GetOrCreatePipeline(
|
||||
GLenum mode,
|
||||
const MG_State::GLState::ProgramObject& program,
|
||||
const MG_State::GLState::VertexArrayObject& vao,
|
||||
const RenderPassEntry& renderPassEntry);
|
||||
|
||||
void DeferDestroyBuffer(VkBufferObject& buffer);
|
||||
void CollectDeferredBufferReleases(Uint32 frameIndex);
|
||||
Bool EnsureFrameUploadBufferCapacity(Uint32 frameIndex, Bool isIndexBuffer, VkDeviceSize requiredEndOffset,
|
||||
VkDeviceSize minCapacity, VkBufferUsageFlags usage);
|
||||
Bool UploadAndBindVertexStreams(const VertexInputStateFactory::BackendVertexInputState& vertexInputState,
|
||||
const DrawArrayPayload& payload, VkCommandBuffer commandBuffer);
|
||||
Bool UploadAndBindVertexStreams(VkCommandBuffer commandBuffer, const MG_State::GLState::VertexArrayObject& vao);
|
||||
Bool InitializeBlitResources();
|
||||
void ShutdownBlitResources();
|
||||
Bool TryBlitToDefaultFramebufferWithShader(FrameContext::FrameData& frame,
|
||||
MG_State::GLState::FramebufferObject& readFbo,
|
||||
MG_State::GLState::FramebufferObject& drawFbo,
|
||||
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
||||
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||
GLenum filter);
|
||||
Bool MaterializePendingClearForTexture(VkCommandBuffer commandBuffer,
|
||||
MG_State::GLState::ITextureObject& texture);
|
||||
VkPipeline GetOrCreateBlitPipeline(const RenderPassEntry& renderPassEntry);
|
||||
|
||||
void ShutdownSwapchain();
|
||||
|
||||
// Static functions
|
||||
static Int GetPresentQueueFamilyIndex(const PhysicalDevice& physicalDevice, VkSurfaceKHR surface,
|
||||
const Vector<VkQueueFamilyProperties>& queueFamilies,
|
||||
Int preferredFamilyIndex = -1);
|
||||
@@ -212,10 +216,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
static Bool GetMoreCapablePhysicalDevice(VkPhysicalDevice newVkDevice, VkSurfaceKHR surface,
|
||||
const PhysicalDevice& compareWithDevice,
|
||||
PhysicalDevice& outBetterDevice);
|
||||
Uint32 FindMemoryType(Uint32 typeFilter, VkMemoryPropertyFlags properties) const;
|
||||
static Uint64 BuildPendingClearKey(Uint drawFboExternalIndex, Bool targetsDefaultFramebuffer);
|
||||
static Bool HasStencilComponent(VkFormat format);
|
||||
static VkFormat FindSupportedDepthStencilFormat(VkPhysicalDevice physicalDevice);
|
||||
static constexpr VkDynamicState s_dynamicStates[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
|
||||
static constexpr const char* s_validationLayerNames[] = {"VK_LAYER_KHRONOS_validation"};
|
||||
static constexpr const char* s_deviceExtensionNames[] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace MobileGL::MG_Impl::EGLImpl {
|
||||
if (!MG_State::pEGLContext) {
|
||||
MGLOG_E("pEGLContext is null. MG_State may not be initialized.");
|
||||
}
|
||||
return MG_State::pEGLContext;
|
||||
return MG_State::pEGLContext.get();
|
||||
}
|
||||
|
||||
MG_Backend::BackendObject* GetBackendObject(EGLStateContext* state) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,24 +9,22 @@
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
|
||||
GLboolean IsBuffer(GLuint buffer);
|
||||
void DeleteBuffers(GLsizei n, const GLuint* buffers);
|
||||
void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length);
|
||||
GLboolean UnmapBuffer(GLenum target);
|
||||
void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
|
||||
void* MapBuffer(GLenum target, GLenum access);
|
||||
void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset,
|
||||
GLsizeiptr size);
|
||||
void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
|
||||
void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
|
||||
void BindBuffer(GLenum target, GLuint buffer);
|
||||
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);
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
|
||||
GLboolean IsBuffer(GLuint buffer);
|
||||
void DeleteBuffers(GLsizei n, const GLuint* buffers);
|
||||
void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length);
|
||||
GLboolean UnmapBuffer(GLenum target);
|
||||
void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
|
||||
void* MapBuffer(GLenum target, GLenum access);
|
||||
void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset,
|
||||
GLsizeiptr size);
|
||||
void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
|
||||
void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
|
||||
void BindBuffer(GLenum target, GLuint buffer);
|
||||
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);
|
||||
|
||||
} // namespace MG_Impl::GLImpl
|
||||
} // namespace MobileGL
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -13,105 +13,100 @@
|
||||
#include <MG_Util/Converters/MGToGL/BufferEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToStr/BufferEnumConverter.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
namespace BufferImpl {
|
||||
Bool ValidateBufferTarget(BufferTarget target) {
|
||||
if (target == BufferTarget::Unknown) {
|
||||
using namespace MG_Util;
|
||||
String bufferTargetStr = ConvertBufferTargetToString(target);
|
||||
String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target));
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget",
|
||||
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target == BufferTarget::Index && MG_State::pGLContext->GetBoundVertexArray() == nullptr) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl",
|
||||
"ValidateBufferTarget",
|
||||
"No vertex array object is bound."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateBufferBindingPointTarget(BufferTarget target) {
|
||||
if (target != BufferTarget::Uniform && target != BufferTarget::AtomicCounter &&
|
||||
target != BufferTarget::TransformFeedback && target != BufferTarget::ShaderStorage) {
|
||||
using namespace MG_Util;
|
||||
String bufferTargetStr = ConvertBufferTargetToString(target);
|
||||
String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target));
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget",
|
||||
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateBufferName(Uint index, Bool allowZero) {
|
||||
if (index == 0) {
|
||||
if (allowZero) return true;
|
||||
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl",
|
||||
"ValidateBufferName",
|
||||
"Buffer name 0 is not valid."));
|
||||
return false;
|
||||
}
|
||||
Bool isValid = MG_State::pGLContext->ValidateBufferName(index);
|
||||
if (isValid) return true;
|
||||
namespace MobileGL::MG_Impl::GLImpl::BufferImpl {
|
||||
Bool ValidateBufferTarget(BufferTarget target) {
|
||||
if (target == BufferTarget::Unknown) {
|
||||
using namespace MG_Util;
|
||||
String bufferTargetStr = ConvertBufferTargetToString(target);
|
||||
String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target));
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferName",
|
||||
std::format("Buffer name {} is not valid.", index)));
|
||||
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget",
|
||||
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
Bool ValidateBufferUsage(BufferUsage usage) {
|
||||
if (usage != BufferUsage::Unknown) {
|
||||
return true;
|
||||
}
|
||||
if (target == BufferTarget::Index && MG_State::pGLContext->GetBoundVertexArray() == nullptr) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl",
|
||||
"ValidateBufferTarget",
|
||||
"No vertex array object is bound."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateBufferBindingPointTarget(BufferTarget target) {
|
||||
if (target != BufferTarget::Uniform && target != BufferTarget::AtomicCounter &&
|
||||
target != BufferTarget::TransformFeedback && target != BufferTarget::ShaderStorage) {
|
||||
using namespace MG_Util;
|
||||
String bufferUsageStr = ConvertBufferUsageToString(usage);
|
||||
String glUsageStr = ConvertGLEnumToString(ConvertBufferUsageToGLEnum(usage));
|
||||
String bufferTargetStr = ConvertBufferTargetToString(target);
|
||||
String glTargetStr = ConvertGLEnumToString(ConvertBufferTargetToGLEnum(target));
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferTarget",
|
||||
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateBufferName(Uint index, Bool allowZero) {
|
||||
if (index == 0) {
|
||||
if (allowZero) return true;
|
||||
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferName",
|
||||
"Buffer name 0 is not valid."));
|
||||
return false;
|
||||
}
|
||||
Bool isValid = MG_State::pGLContext->ValidateBufferName(index);
|
||||
if (isValid) return true;
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferName",
|
||||
std::format("Buffer name {} is not valid.", index)));
|
||||
return false;
|
||||
}
|
||||
|
||||
Bool ValidateBufferUsage(BufferUsage usage) {
|
||||
if (usage != BufferUsage::Unknown) {
|
||||
return true;
|
||||
}
|
||||
using namespace MG_Util;
|
||||
String bufferUsageStr = ConvertBufferUsageToString(usage);
|
||||
String glUsageStr = ConvertGLEnumToString(ConvertBufferUsageToGLEnum(usage));
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferUsage",
|
||||
std::format("Usage {} ({}) is not one of the allowable values.", bufferUsageStr, glUsageStr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
Bool ValidateBufferMappingAccess(Flags<BufferMappingAccessBit> accessBits) {
|
||||
if (accessBits == BufferMappingAccessBit::Null) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl",
|
||||
"ValidateBufferMappingAccess",
|
||||
"Access bits cannot be null."));
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto validBits = BufferMappingAccessBit::Read | BufferMappingAccessBit::Write |
|
||||
BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer |
|
||||
BufferMappingAccessBit::FlushExplicit | BufferMappingAccessBit::Unsynchronized |
|
||||
BufferMappingAccessBit::Persistent | BufferMappingAccessBit::Coherent;
|
||||
|
||||
if ((accessBits & validBits) != accessBits) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl/BufferImpl", "ValidateBufferUsage",
|
||||
std::format("Usage {} ({}) is not one of the allowable values.", bufferUsageStr, glUsageStr)));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferMappingAccess",
|
||||
"Access bits cannot contain invalid flags."));
|
||||
return false;
|
||||
}
|
||||
|
||||
Bool ValidateBufferMappingAccess(Flags<BufferMappingAccessBit> accessBits) {
|
||||
if (accessBits == BufferMappingAccessBit::Null) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl",
|
||||
"ValidateBufferMappingAccess",
|
||||
"Access bits cannot be null."));
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto validBits = BufferMappingAccessBit::Read | BufferMappingAccessBit::Write |
|
||||
BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer |
|
||||
BufferMappingAccessBit::FlushExplicit | BufferMappingAccessBit::Unsynchronized |
|
||||
BufferMappingAccessBit::Persistent | BufferMappingAccessBit::Coherent;
|
||||
|
||||
if ((accessBits & validBits) != accessBits) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferMappingAccess",
|
||||
"Access bits cannot contain invalid flags."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace BufferImpl
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
return true;
|
||||
}
|
||||
} // namespace MobileGL::MG_Impl::GLImpl::BufferImpl
|
||||
|
||||
@@ -10,12 +10,10 @@
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/BufferState/BufferObject.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
namespace BufferImpl {
|
||||
Bool ValidateBufferTarget(BufferTarget target);
|
||||
Bool ValidateBufferName(Uint index, Bool allowZero = false);
|
||||
Bool ValidateBufferUsage(BufferUsage usage);
|
||||
Bool ValidateBufferMappingAccess(Flags<BufferMappingAccessBit> accessBits);
|
||||
Bool ValidateBufferBindingPointTarget(BufferTarget target);
|
||||
} // namespace BufferImpl
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
namespace MobileGL::MG_Impl::GLImpl::BufferImpl {
|
||||
Bool ValidateBufferTarget(BufferTarget target);
|
||||
Bool ValidateBufferName(Uint index, Bool allowZero = false);
|
||||
Bool ValidateBufferUsage(BufferUsage usage);
|
||||
Bool ValidateBufferMappingAccess(Flags<BufferMappingAccessBit> accessBits);
|
||||
Bool ValidateBufferBindingPointTarget(BufferTarget target);
|
||||
} // namespace MobileGL::MG_Impl::GLImpl::BufferImpl
|
||||
|
||||
@@ -9,34 +9,31 @@
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount,
|
||||
GLsizei stride);
|
||||
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
|
||||
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||
const void* indices, GLint basevertex);
|
||||
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
|
||||
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLint basevertex, GLuint baseinstance);
|
||||
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLint basevertex);
|
||||
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLuint baseinstance);
|
||||
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount);
|
||||
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect);
|
||||
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
||||
GLuint baseinstance);
|
||||
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
||||
void DrawArraysIndirect(GLenum mode, const void* indirect);
|
||||
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex);
|
||||
void DrawArrays(GLenum mode, GLint first, GLsizei count);
|
||||
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
|
||||
GLsizei drawcount);
|
||||
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
|
||||
GLsizei drawcount, const GLint* basevertex);
|
||||
void Clear(GLbitfield mask);
|
||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
|
||||
} // namespace MG_Impl::GLImpl
|
||||
} // namespace MobileGL
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride);
|
||||
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
|
||||
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
||||
const void* indices, GLint basevertex);
|
||||
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
|
||||
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLint basevertex, GLuint baseinstance);
|
||||
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLint basevertex);
|
||||
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
||||
GLsizei instancecount, GLuint baseinstance);
|
||||
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount);
|
||||
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect);
|
||||
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
||||
GLuint baseinstance);
|
||||
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
||||
void DrawArraysIndirect(GLenum mode, const void* indirect);
|
||||
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex);
|
||||
void DrawArrays(GLenum mode, GLint first, GLsizei count);
|
||||
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
|
||||
GLsizei drawcount);
|
||||
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
|
||||
GLsizei drawcount, const GLint* basevertex);
|
||||
void Clear(GLbitfield mask);
|
||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -38,11 +38,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
RenderbufferTarget rbTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
|
||||
if (!FramebufferImpl::ValidateRenderbufferTarget(rbTarget)) return;
|
||||
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(rbTarget);
|
||||
auto renderbufferObject = bindingSlot.GetBoundObject();
|
||||
auto& renderbufferObject = bindingSlot.GetBoundObject();
|
||||
if (!renderbufferObject) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorage_State",
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorage_State",
|
||||
"Renderbuffer target is bound to no renderbuffer object."));
|
||||
return;
|
||||
}
|
||||
@@ -50,7 +50,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (!TextureImpl::ValidateTextureInternalFormat(format)) return;
|
||||
if (width < 0 || height < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorage_State",
|
||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorage_State",
|
||||
"Width and height must be non-negative."));
|
||||
return;
|
||||
}
|
||||
@@ -74,10 +74,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GenRenderbuffers_State", "n must be non-negative"));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenRenderbuffers_State", "n must be non-negative"));
|
||||
return;
|
||||
}
|
||||
auto renderbufferNames = MG_State::pGLContext->GenRenderbufferNames(n);
|
||||
static thread_local Vector<GLuint> renderbufferNames;
|
||||
MG_State::pGLContext->GenRenderbufferNames(n, renderbufferNames);
|
||||
Memcpy(renderbuffers, renderbufferNames.data(), sizeof(GLuint) * static_cast<SizeT>(n));
|
||||
}
|
||||
|
||||
@@ -85,10 +86,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GenFramebuffers_State", "n must be non-negative"));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenFramebuffers_State", "n must be non-negative"));
|
||||
return;
|
||||
}
|
||||
auto framebuffersNames = MG_State::pGLContext->GenFramebufferNames(n);
|
||||
static thread_local Vector<GLuint> framebuffersNames;
|
||||
MG_State::pGLContext->GenFramebufferNames(n, framebuffersNames);
|
||||
Memcpy(framebuffers, framebuffersNames.data(), sizeof(GLuint) * static_cast<SizeT>(n));
|
||||
}
|
||||
|
||||
@@ -119,11 +121,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (!TextureImpl::ValidateTextureName(texture, true)) return;
|
||||
|
||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
|
||||
auto framebufferObject = bindingSlot.GetBoundObject();
|
||||
auto& framebufferObject = bindingSlot.GetBoundObject();
|
||||
if (!framebufferObject) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferTexture2D_State",
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferTexture2D_State",
|
||||
"Framebuffer target is bound to no framebuffer object."));
|
||||
return;
|
||||
}
|
||||
@@ -133,11 +135,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
return;
|
||||
}
|
||||
|
||||
auto textureObject = MG_State::pGLContext->GetTextureObject(texture);
|
||||
auto& textureObject = MG_State::pGLContext->GetTextureObject(texture);
|
||||
if (!textureObject) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferTexture2D_State",
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferTexture2D_State",
|
||||
std::format("Texture object {} is not valid.", texture)));
|
||||
return;
|
||||
}
|
||||
@@ -166,11 +168,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return;
|
||||
if (!FramebufferImpl::ValidateRenderbufferName(renderbuffer)) return;
|
||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
|
||||
auto framebufferObject = bindingSlot.GetBoundObject();
|
||||
auto& framebufferObject = bindingSlot.GetBoundObject();
|
||||
if (!framebufferObject) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferRenderbuffer_State",
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferRenderbuffer_State",
|
||||
"Framebuffer target is bound to no framebuffer object."));
|
||||
return;
|
||||
}
|
||||
@@ -180,11 +182,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
return;
|
||||
}
|
||||
|
||||
auto renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer);
|
||||
auto& renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer);
|
||||
if (!renderbufferObject) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferRenderbuffer_State",
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferRenderbuffer_State",
|
||||
std::format("Renderbuffer object {} is not valid.", renderbuffer)));
|
||||
return;
|
||||
}
|
||||
@@ -196,18 +198,18 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`n` is less than 0."));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`n` is less than 0."));
|
||||
return;
|
||||
} else if (n > MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`n` is greater than `GL_MAX_DRAW_BUFFERS`."));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`n` is greater than `GL_MAX_DRAW_BUFFERS`."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get bound framebuffer
|
||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
|
||||
auto fbo = bindingSlot.GetBoundObject();
|
||||
auto& fbo = bindingSlot.GetBoundObject();
|
||||
bool isDefaultFBO = (fbo == FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
|
||||
|
||||
static int existenceMap[(SizeT)FramebufferAttachmentType::FramebufferAttachmentTypeCount] = {-1};
|
||||
@@ -220,7 +222,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (attType == FramebufferAttachmentType::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
std::format("bufs[{}] = {} is not an accepted value.", i,
|
||||
MG_Util::ConvertGLEnumToString(bufs[i]))));
|
||||
return;
|
||||
@@ -230,7 +232,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
attType <= FramebufferAttachmentType::Color31) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>(
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", __func__,
|
||||
std::format(
|
||||
"FBO is default FBO, but bufs[{}] = {} is one of the `GL_COLOR_ATTACHMENTn` tokens.", i,
|
||||
@@ -242,7 +244,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
attType <= FramebufferAttachmentType::BackRight) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>(
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", __func__,
|
||||
std::format("FBO is not default FBO, but bufs[{}] = {} is anything other than `GL_NONE` or "
|
||||
"one of the `GL_COLOR_ATTACHMENTn` tokens.",
|
||||
@@ -253,7 +255,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (attType != FramebufferAttachmentType::None && existenceMap[(SizeT)attType] >= 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
std::format("a symbolic constant other than `GL_NONE` appears "
|
||||
"more than once in bufs. bufs[{}] == bufs[{}] == {}.",
|
||||
i, existenceMap[(SizeT)attType],
|
||||
@@ -267,7 +269,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
(SizeT)FramebufferAttachmentType::Color0 + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
std::format("bufs[{}] == {} indicates a color buffer that does "
|
||||
"not exist in the current GL context.",
|
||||
i, MG_Util::ConvertGLEnumToString(bufs[i]))));
|
||||
@@ -297,7 +299,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (attType == FramebufferAttachmentType::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>(
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", __func__,
|
||||
std::format("`mode` = {} is not an accepted value.", MG_Util::ConvertGLEnumToString(mode))));
|
||||
return;
|
||||
@@ -305,7 +307,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
|
||||
// Get bound framebuffer
|
||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
|
||||
auto fbo = bindingSlot.GetBoundObject();
|
||||
auto& fbo = bindingSlot.GetBoundObject();
|
||||
fbo->SetReadBuffer(attType);
|
||||
}
|
||||
|
||||
@@ -313,13 +315,13 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteRenderbuffers_State", "n must be non-negative."));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteRenderbuffers_State", "n must be non-negative."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!renderbuffers) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteRenderbuffers_State",
|
||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteRenderbuffers_State",
|
||||
"Renderbuffer names array cannot be null."));
|
||||
return;
|
||||
}
|
||||
@@ -336,13 +338,13 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteFramebuffers_State", "n must be non-negative."));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteFramebuffers_State", "n must be non-negative."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!framebuffers) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteFramebuffers_State",
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteFramebuffers_State",
|
||||
"Framebuffer names array cannot be null."));
|
||||
return;
|
||||
}
|
||||
@@ -360,11 +362,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return GL_FRAMEBUFFER_UNDEFINED;
|
||||
|
||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
|
||||
auto framebufferObject = bindingSlot.GetBoundObject();
|
||||
auto& framebufferObject = bindingSlot.GetBoundObject();
|
||||
if (!framebufferObject) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "CheckFramebufferStatus_State",
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CheckFramebufferStatus_State",
|
||||
"Framebuffer target is bound to no framebuffer object."));
|
||||
return GL_FRAMEBUFFER_UNDEFINED;
|
||||
}
|
||||
@@ -382,11 +384,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
|
||||
if (!FramebufferImpl::ValidateRenderbufferTarget(renderbufferTarget)) return;
|
||||
|
||||
auto renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer);
|
||||
if (!renderbufferObject) {
|
||||
Bool doesRenderbufferCreated = MG_State::pGLContext->ValidateRenderbufferObject(renderbuffer);
|
||||
if (!doesRenderbufferCreated) {
|
||||
MG_State::pGLContext->CreateRenderbufferObject(renderbuffer);
|
||||
renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer);
|
||||
}
|
||||
auto& renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer);
|
||||
|
||||
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(renderbufferTarget);
|
||||
bindingSlot.Bind(renderbufferObject);
|
||||
@@ -403,11 +405,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
FramebufferTarget framebufferTarget = MG_Util::ConvertGLEnumToFramebufferTarget(target);
|
||||
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return;
|
||||
|
||||
auto framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
|
||||
if (!framebufferObject) {
|
||||
Bool doesFramebufferCreated = MG_State::pGLContext->ValidateFramebufferObject(framebuffer);
|
||||
if (!doesFramebufferCreated) {
|
||||
MG_State::pGLContext->CreateFramebufferObject(framebuffer);
|
||||
framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
|
||||
}
|
||||
auto& framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
|
||||
|
||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
|
||||
bindingSlot.Bind(framebufferObject);
|
||||
@@ -419,11 +421,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
|
||||
if (!FramebufferImpl::ValidateRenderbufferTarget(renderbufferTarget)) return;
|
||||
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(renderbufferTarget);
|
||||
auto renderbufferObject = bindingSlot.GetBoundObject();
|
||||
auto& renderbufferObject = bindingSlot.GetBoundObject();
|
||||
if (!renderbufferObject) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetRenderbufferParameteriv_State",
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetRenderbufferParameteriv_State",
|
||||
"Renderbuffer target is bound to no renderbuffer object."));
|
||||
return;
|
||||
}
|
||||
@@ -462,7 +464,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>(
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "GetRenderbufferParameteriv_State",
|
||||
std::format("pname {} is not an accepted value.", MG_Util::ConvertGLEnumToString(pname))));
|
||||
return;
|
||||
@@ -492,7 +494,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
// Check width/height
|
||||
if (width < 0 || height < 0) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
"Width and height must be non-negative"));
|
||||
return;
|
||||
}
|
||||
@@ -501,7 +503,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid format"));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid format"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -509,17 +511,17 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid pixel data type"));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid pixel data type"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get bound framebuffer
|
||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
|
||||
auto framebufferObject = bindingSlot.GetBoundObject();
|
||||
auto& framebufferObject = bindingSlot.GetBoundObject();
|
||||
|
||||
if (!framebufferObject) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
"No framebuffer bound to read target"));
|
||||
return;
|
||||
}
|
||||
@@ -528,7 +530,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (!framebufferObject->CheckCompleteness()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidFramebufferOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Framebuffer is incomplete"));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Framebuffer is incomplete"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -537,7 +539,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil).IsValid()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
"No stencil buffer for stencil index format"));
|
||||
return;
|
||||
}
|
||||
@@ -545,7 +547,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Depth).IsValid()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
"No depth buffer for depth component format"));
|
||||
return;
|
||||
}
|
||||
@@ -554,7 +556,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
!framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil).IsValid()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
"No depth/stencil buffer for depth-stencil format"));
|
||||
return;
|
||||
}
|
||||
@@ -563,7 +565,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (texturePixelDataType != TexturePixelDataType::UnsignedInt248 &&
|
||||
texturePixelDataType != TexturePixelDataType::Float32UnsignedInt248Rev) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
"Invalid type for depth-stencil format"));
|
||||
return;
|
||||
}
|
||||
@@ -577,7 +579,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
// Check if PBO is mapped
|
||||
if (pixelPackBufferObject->IsMapped()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
"Pixel pack buffer is currently mapped"));
|
||||
return;
|
||||
}
|
||||
@@ -587,7 +589,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (reinterpret_cast<uintptr_t>(pixels) % typeSize != 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
"Pixel data not aligned for pixel pack buffer"));
|
||||
return;
|
||||
}
|
||||
@@ -595,11 +597,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
|
||||
// Check multisampling
|
||||
if (framebufferObject->GetAttachment(FramebufferAttachmentType::Color0).IsRenderbuffer()) {
|
||||
auto rbo = framebufferObject->GetAttachment(FramebufferAttachmentType::Color0).GetRenderbuffer();
|
||||
auto& rbo = framebufferObject->GetAttachment(FramebufferAttachmentType::Color0).GetRenderbuffer();
|
||||
if (rbo && rbo->GetSamples() > 1) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
|
||||
"ReadPixels not supported for multisampled framebuffers"));
|
||||
return;
|
||||
}
|
||||
@@ -732,6 +734,6 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
namespace FramebufferImpl {
|
||||
DefaultFramebufferInfo* pDefaultFramebufferInfo;
|
||||
UniquePtr<DefaultFramebufferInfo> pDefaultFramebufferInfo;
|
||||
} // namespace FramebufferImpl
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -11,51 +11,49 @@
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/Core.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
||||
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
||||
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
|
||||
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
|
||||
void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
|
||||
GLsizei height);
|
||||
void RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
|
||||
GLboolean IsRenderbuffer(GLuint renderbuffer);
|
||||
void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
|
||||
void GenRenderbuffers(GLsizei n, GLuint* renderbuffers);
|
||||
void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
|
||||
void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers);
|
||||
void BindRenderbuffer(GLenum target, GLuint renderbuffer);
|
||||
void SampleMaski(GLuint maskNumber, GLbitfield mask);
|
||||
GLboolean IsFramebuffer(GLuint framebuffer);
|
||||
void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
|
||||
void GenFramebuffers(GLsizei n, GLuint* framebuffers);
|
||||
void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
|
||||
void FramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level,
|
||||
GLint zoffset);
|
||||
void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||
void FramebufferTexture1D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||
void FramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level);
|
||||
void DrawBuffer(GLenum buf);
|
||||
void DrawBuffers(GLsizei n, const GLenum* bufs);
|
||||
void ReadBuffer(GLenum src);
|
||||
void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
|
||||
GLenum CheckFramebufferStatus(GLenum target);
|
||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
||||
GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
void BindFramebuffer(GLenum target, GLuint framebuffer);
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
||||
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
||||
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
|
||||
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
|
||||
void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
|
||||
GLsizei height);
|
||||
void RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
|
||||
GLboolean IsRenderbuffer(GLuint renderbuffer);
|
||||
void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
|
||||
void GenRenderbuffers(GLsizei n, GLuint* renderbuffers);
|
||||
void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
|
||||
void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers);
|
||||
void BindRenderbuffer(GLenum target, GLuint renderbuffer);
|
||||
void SampleMaski(GLuint maskNumber, GLbitfield mask);
|
||||
GLboolean IsFramebuffer(GLuint framebuffer);
|
||||
void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
|
||||
void GenFramebuffers(GLsizei n, GLuint* framebuffers);
|
||||
void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
|
||||
void FramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level,
|
||||
GLint zoffset);
|
||||
void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||
void FramebufferTexture1D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||
void FramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level);
|
||||
void DrawBuffer(GLenum buf);
|
||||
void DrawBuffers(GLsizei n, const GLenum* bufs);
|
||||
void ReadBuffer(GLenum src);
|
||||
void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers);
|
||||
GLenum CheckFramebufferStatus(GLenum target);
|
||||
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
||||
GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
void BindFramebuffer(GLenum target, GLuint framebuffer);
|
||||
|
||||
namespace FramebufferImpl {
|
||||
struct DefaultFramebufferInfo {
|
||||
SharedPtr<MG_State::GLState::FramebufferObject> defaultFBO;
|
||||
SharedPtr<MG_State::GLState::ITextureObject> colorAttachment;
|
||||
SharedPtr<MG_State::GLState::ITextureObject> depthAttachment;
|
||||
SharedPtr<MG_State::GLState::ITextureObject> stencilAttachment;
|
||||
};
|
||||
namespace FramebufferImpl {
|
||||
struct DefaultFramebufferInfo {
|
||||
SharedPtr<MG_State::GLState::FramebufferObject> defaultFBO;
|
||||
SharedPtr<MG_State::GLState::ITextureObject> colorAttachment;
|
||||
SharedPtr<MG_State::GLState::ITextureObject> depthAttachment;
|
||||
SharedPtr<MG_State::GLState::ITextureObject> stencilAttachment;
|
||||
};
|
||||
|
||||
extern DefaultFramebufferInfo* pDefaultFramebufferInfo;
|
||||
} // namespace FramebufferImpl
|
||||
} // namespace MG_Impl::GLImpl
|
||||
} // namespace MobileGL
|
||||
extern UniquePtr<DefaultFramebufferInfo> pDefaultFramebufferInfo;
|
||||
} // namespace FramebufferImpl
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -13,85 +13,82 @@
|
||||
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToStr/FramebufferEnumConverter.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
namespace FramebufferImpl {
|
||||
Bool ValidateFramebufferTarget(FramebufferTarget target) {
|
||||
if (target == FramebufferTarget::Unknown) {
|
||||
using namespace MG_Util;
|
||||
String bufferTargetStr = ConvertFramebufferTargetToString(target);
|
||||
String glTargetStr = ConvertGLEnumToString(ConvertFramebufferTargetToGLEnum(target));
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferTarget",
|
||||
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateFramebufferName(Uint index, Bool allowZero) {
|
||||
if (index == 0 && !allowZero) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferName",
|
||||
"Framebuffer name 0 is not valid in this situation."));
|
||||
return false;
|
||||
}
|
||||
Bool isValid = MG_State::pGLContext->ValidateFramebufferName(index);
|
||||
if (isValid) return true;
|
||||
namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
|
||||
Bool ValidateFramebufferTarget(FramebufferTarget target) {
|
||||
if (target == FramebufferTarget::Unknown) {
|
||||
using namespace MG_Util;
|
||||
String bufferTargetStr = ConvertFramebufferTargetToString(target);
|
||||
String glTargetStr = ConvertGLEnumToString(ConvertFramebufferTargetToGLEnum(target));
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferName",
|
||||
std::format("Framebuffer name {} is not valid.", index)));
|
||||
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferTarget",
|
||||
std::format("Target {} ({}) is not valid.", bufferTargetStr, glTargetStr)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateFramebufferAttachmentType(FramebufferAttachmentType attachment) {
|
||||
if (attachment == FramebufferAttachmentType::Unknown) {
|
||||
using namespace MG_Util;
|
||||
String attachmentStr = ConvertFramebufferAttachmentTypeToString(attachment);
|
||||
String glAttachmentStr = ConvertGLEnumToString(ConvertFramebufferAttachmentTypeToGLEnum(attachment));
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferAttachmentType",
|
||||
std::format("Attachment type {} ({}) is not valid.", attachmentStr, glAttachmentStr)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateRenderbufferTarget(RenderbufferTarget target) {
|
||||
if (target == RenderbufferTarget::Unknown) {
|
||||
using namespace MG_Util;
|
||||
String renderbufferTargetStr = ConvertRenderbufferTargetToString(target);
|
||||
String glTargetStr = ConvertGLEnumToString(ConvertRenderbufferTargetToGLEnum(target));
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferTarget",
|
||||
std::format("Target {} ({}) is not valid.", renderbufferTargetStr, glTargetStr)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateRenderbufferName(Uint index, Bool allowZero) {
|
||||
if (index == 0 && !allowZero) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferName",
|
||||
"Renderbuffer name 0 is not valid in this situation."));
|
||||
return false;
|
||||
}
|
||||
Bool isValid = MG_State::pGLContext->ValidateRenderbufferName(index);
|
||||
if (isValid) return true;
|
||||
Bool ValidateFramebufferName(Uint index, Bool allowZero) {
|
||||
if (index == 0 && !allowZero) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferName",
|
||||
std::format("Renderbuffer name {} is not valid.", index)));
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferName",
|
||||
"Framebuffer name 0 is not valid in this situation."));
|
||||
return false;
|
||||
}
|
||||
} // namespace FramebufferImpl
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
Bool isValid = MG_State::pGLContext->ValidateFramebufferName(index);
|
||||
if (isValid) return true;
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferName",
|
||||
std::format("Framebuffer name {} is not valid.", index)));
|
||||
return false;
|
||||
}
|
||||
|
||||
Bool ValidateFramebufferAttachmentType(FramebufferAttachmentType attachment) {
|
||||
if (attachment == FramebufferAttachmentType::Unknown) {
|
||||
using namespace MG_Util;
|
||||
String attachmentStr = ConvertFramebufferAttachmentTypeToString(attachment);
|
||||
String glAttachmentStr = ConvertGLEnumToString(ConvertFramebufferAttachmentTypeToGLEnum(attachment));
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl/FramebufferImpl", "ValidateFramebufferAttachmentType",
|
||||
std::format("Attachment type {} ({}) is not valid.", attachmentStr, glAttachmentStr)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateRenderbufferTarget(RenderbufferTarget target) {
|
||||
if (target == RenderbufferTarget::Unknown) {
|
||||
using namespace MG_Util;
|
||||
String renderbufferTargetStr = ConvertRenderbufferTargetToString(target);
|
||||
String glTargetStr = ConvertGLEnumToString(ConvertRenderbufferTargetToGLEnum(target));
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferTarget",
|
||||
std::format("Target {} ({}) is not valid.", renderbufferTargetStr, glTargetStr)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateRenderbufferName(Uint index, Bool allowZero) {
|
||||
if (index == 0 && !allowZero) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferName",
|
||||
"Renderbuffer name 0 is not valid in this situation."));
|
||||
return false;
|
||||
}
|
||||
Bool isValid = MG_State::pGLContext->ValidateRenderbufferName(index);
|
||||
if (isValid) return true;
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/FramebufferImpl", "ValidateRenderbufferName",
|
||||
std::format("Renderbuffer name {} is not valid.", index)));
|
||||
return false;
|
||||
}
|
||||
} // namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl
|
||||
|
||||
@@ -10,12 +10,10 @@
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
namespace FramebufferImpl {
|
||||
Bool ValidateFramebufferTarget(FramebufferTarget target);
|
||||
Bool ValidateFramebufferName(Uint index, Bool allowZero = true);
|
||||
Bool ValidateFramebufferAttachmentType(FramebufferAttachmentType attachment);
|
||||
Bool ValidateRenderbufferTarget(RenderbufferTarget target);
|
||||
Bool ValidateRenderbufferName(Uint index, Bool allowZero = true);
|
||||
} // namespace FramebufferImpl
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
|
||||
Bool ValidateFramebufferTarget(FramebufferTarget target);
|
||||
Bool ValidateFramebufferName(Uint index, Bool allowZero = true);
|
||||
Bool ValidateFramebufferAttachmentType(FramebufferAttachmentType attachment);
|
||||
Bool ValidateRenderbufferTarget(RenderbufferTarget target);
|
||||
Bool ValidateRenderbufferName(Uint index, Bool allowZero = true);
|
||||
} // namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
// End of Source File Header
|
||||
|
||||
#include "GL_Getter.h"
|
||||
#include "GL/gl.h"
|
||||
#include "MG_Util/Debug/Log.h"
|
||||
#include <Config.h>
|
||||
#include <MGGitHash.h>
|
||||
#include <MG_State/GLState/Core.h>
|
||||
@@ -127,7 +125,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (!params) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetIntegerv", "params pointer cannot be null"));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetIntegerv", "params pointer cannot be null"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -146,9 +144,9 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
*params = 0; // TODO
|
||||
break;
|
||||
case GL_ARRAY_BUFFER_BINDING: {
|
||||
auto obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex).GetBoundObject();
|
||||
auto& obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex).GetBoundObject();
|
||||
if (obj)
|
||||
*params = obj->GetExternalIndex();
|
||||
*params = (GLint)obj->GetExternalIndex();
|
||||
else
|
||||
*params = 0;
|
||||
break;
|
||||
@@ -256,14 +254,14 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
break;
|
||||
case GL_CURRENT_PROGRAM: {
|
||||
const auto& currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
||||
*params = currentProgram ? currentProgram->GetExternalIndex() : 0;
|
||||
*params = currentProgram ? (GLint)currentProgram->GetExternalIndex() : 0;
|
||||
break;
|
||||
}
|
||||
case GL_DEPTH_CLEAR_VALUE:
|
||||
*params = MG_State::pGLContext->GetClearDepth();
|
||||
*params = (GLint)MG_State::pGLContext->GetClearDepth();
|
||||
break;
|
||||
case GL_DEPTH_FUNC:
|
||||
*params = MG_Util::ConvertDepthTestFuncToGLEnum(MG_State::pGLContext->GetDepthFunc());
|
||||
*params = (GLint)MG_Util::ConvertDepthTestFuncToGLEnum(MG_State::pGLContext->GetDepthFunc());
|
||||
break;
|
||||
case GL_DEPTH_RANGE:
|
||||
*params = 0; // TODO
|
||||
@@ -288,12 +286,12 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
break;
|
||||
case GL_DRAW_FRAMEBUFFER_BINDING: {
|
||||
const auto& FBO = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||
*params = FBO ? FBO->GetExternalIndex() : 0;
|
||||
*params = FBO ? (GLint)FBO->GetExternalIndex() : 0;
|
||||
break;
|
||||
}
|
||||
case GL_READ_FRAMEBUFFER_BINDING: {
|
||||
const auto& FBO = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
|
||||
*params = FBO ? FBO->GetExternalIndex() : 0;
|
||||
*params = FBO ? (GLint)FBO->GetExternalIndex() : 0;
|
||||
break;
|
||||
}
|
||||
case GL_ELEMENT_ARRAY_BUFFER_BINDING: {
|
||||
@@ -302,7 +300,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
break;
|
||||
}
|
||||
const auto& bufferObject = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Index).GetBoundObject();
|
||||
*params = bufferObject ? bufferObject->GetExternalIndex() : 0;
|
||||
*params = bufferObject ? (GLint)bufferObject->GetExternalIndex() : 0;
|
||||
break;
|
||||
}
|
||||
case GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
|
||||
@@ -886,7 +884,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
default:
|
||||
MGLOG_E("glGetIntegerv: Invalid enum %s (0x%X)", MG_Util::ConvertGLEnumToString(pname).c_str(), pname);
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetIntegerv",
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetIntegerv",
|
||||
std::format("Invalid enum: 0x{:X}", pname)));
|
||||
|
||||
break;
|
||||
@@ -894,7 +892,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
|
||||
GLenum GetError() {
|
||||
ErrorCode errorCode = MG_State::pGLContext->PopGLError().value_or(Error{ErrorCode::NoError, nullptr}).code;
|
||||
return MG_Util::ConvertErrorCodeToGLEnum(errorCode);
|
||||
auto error = MG_State::pGLContext->PopGLError();
|
||||
if (!error || !error->get()) {
|
||||
return GL_NO_ERROR;
|
||||
}
|
||||
return MG_Util::ConvertErrorCodeToGLEnum(error->get()->code);
|
||||
}
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,61 +9,59 @@
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Impl::GLImpl {
|
||||
void AttachShader(GLuint program, GLuint shader);
|
||||
void BindAttribLocation(GLuint program, GLuint index, const GLchar* name);
|
||||
void CompileShader(GLuint shader);
|
||||
GLuint CreateProgram(void);
|
||||
GLuint CreateShader(GLenum type);
|
||||
void DeleteProgram(GLuint program);
|
||||
void DeleteShader(GLuint shader);
|
||||
void DetachShader(GLuint program, GLuint shader);
|
||||
void GetActiveAttrib(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type,
|
||||
GLchar* name);
|
||||
void GetActiveUniform(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type,
|
||||
GLchar* name);
|
||||
void GetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders);
|
||||
GLint GetAttribLocation(GLuint program, const GLchar* name);
|
||||
void GetProgramiv(GLuint program, GLenum pname, GLint* params);
|
||||
void GetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
|
||||
void GetShaderiv(GLuint shader, GLenum pname, GLint* params);
|
||||
void GetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
|
||||
void GetShaderSource(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* source);
|
||||
GLint GetUniformLocation(GLuint program, const GLchar* name);
|
||||
void GetUniformfv(GLuint program, GLint location, GLfloat* params);
|
||||
void GetUniformiv(GLuint program, GLint location, GLint* params);
|
||||
GLboolean IsProgram(GLuint program);
|
||||
GLboolean IsShader(GLuint shader);
|
||||
void LinkProgram(GLuint program);
|
||||
void ShaderSource(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length);
|
||||
void UseProgram(GLuint program);
|
||||
void Uniform1f(GLint location, GLfloat v0);
|
||||
void Uniform2f(GLint location, GLfloat v0, GLfloat v1);
|
||||
void Uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
|
||||
void Uniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
|
||||
void Uniform1i(GLint location, GLint v0);
|
||||
void Uniform2i(GLint location, GLint v0, GLint v1);
|
||||
void Uniform3i(GLint location, GLint v0, GLint v1, GLint v2);
|
||||
void Uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
|
||||
void Uniform1fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void Uniform2fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void Uniform3fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void Uniform4fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void Uniform1iv(GLint location, GLsizei count, const GLint* value);
|
||||
void Uniform2iv(GLint location, GLsizei count, const GLint* value);
|
||||
void Uniform3iv(GLint location, GLsizei count, const GLint* value);
|
||||
void Uniform4iv(GLint location, GLsizei count, const GLint* value);
|
||||
void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
void UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
void UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
GLuint GetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName);
|
||||
void UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
|
||||
void GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params);
|
||||
void GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length,
|
||||
GLchar* uniformBlockName);
|
||||
void BindFragDataLocation(GLuint program, GLuint colorNumber, const char* name);
|
||||
GLint GetFragDataLocation(GLuint program, const char* name);
|
||||
void ValidateProgram(GLuint program);
|
||||
} // namespace MG_Impl::GLImpl
|
||||
} // namespace MobileGL
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
void AttachShader(GLuint program, GLuint shader);
|
||||
void BindAttribLocation(GLuint program, GLuint index, const GLchar* name);
|
||||
void CompileShader(GLuint shader);
|
||||
GLuint CreateProgram(void);
|
||||
GLuint CreateShader(GLenum type);
|
||||
void DeleteProgram(GLuint program);
|
||||
void DeleteShader(GLuint shader);
|
||||
void DetachShader(GLuint program, GLuint shader);
|
||||
void GetActiveAttrib(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type,
|
||||
GLchar* name);
|
||||
void GetActiveUniform(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type,
|
||||
GLchar* name);
|
||||
void GetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders);
|
||||
GLint GetAttribLocation(GLuint program, const GLchar* name);
|
||||
void GetProgramiv(GLuint program, GLenum pname, GLint* params);
|
||||
void GetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
|
||||
void GetShaderiv(GLuint shader, GLenum pname, GLint* params);
|
||||
void GetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
|
||||
void GetShaderSource(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* source);
|
||||
GLint GetUniformLocation(GLuint program, const GLchar* name);
|
||||
void GetUniformfv(GLuint program, GLint location, GLfloat* params);
|
||||
void GetUniformiv(GLuint program, GLint location, GLint* params);
|
||||
GLboolean IsProgram(GLuint program);
|
||||
GLboolean IsShader(GLuint shader);
|
||||
void LinkProgram(GLuint program);
|
||||
void ShaderSource(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length);
|
||||
void UseProgram(GLuint program);
|
||||
void Uniform1f(GLint location, GLfloat v0);
|
||||
void Uniform2f(GLint location, GLfloat v0, GLfloat v1);
|
||||
void Uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
|
||||
void Uniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
|
||||
void Uniform1i(GLint location, GLint v0);
|
||||
void Uniform2i(GLint location, GLint v0, GLint v1);
|
||||
void Uniform3i(GLint location, GLint v0, GLint v1, GLint v2);
|
||||
void Uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
|
||||
void Uniform1fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void Uniform2fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void Uniform3fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void Uniform4fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void Uniform1iv(GLint location, GLsizei count, const GLint* value);
|
||||
void Uniform2iv(GLint location, GLsizei count, const GLint* value);
|
||||
void Uniform3iv(GLint location, GLsizei count, const GLint* value);
|
||||
void Uniform4iv(GLint location, GLsizei count, const GLint* value);
|
||||
void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
void UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
void UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
GLuint GetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName);
|
||||
void UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
|
||||
void GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params);
|
||||
void GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length,
|
||||
GLchar* uniformBlockName);
|
||||
void BindFragDataLocation(GLuint program, GLuint colorNumber, const char* name);
|
||||
GLint GetFragDataLocation(GLuint program, const char* name);
|
||||
void ValidateProgram(GLuint program);
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -7,474 +7,467 @@
|
||||
// End of Source File Header
|
||||
|
||||
#include "GL_RenderState.h"
|
||||
#include "MG_State/GLState/RenderState/RenderState.h"
|
||||
#include "MG_Util/Converters/GLToStr/GLEnumConverter.h"
|
||||
#include <MG_State/GLState/Core.h>
|
||||
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
|
||||
#include <MG_Util/Converters/GLToMG/RenderStateEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToGL/RenderStateEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToStr/RenderStateEnumConverter.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Impl::GLImpl {
|
||||
void Viewport_State(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
if (width < 0 || height < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "Viewport_State",
|
||||
"Width abd height must be non-negative."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetViewport(IntVec4(x, y, width, height));
|
||||
}
|
||||
|
||||
void StencilOpSeparate_State(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void StencilOp_State(GLenum fail, GLenum zfail, GLenum zpass) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void StencilMaskSeparate_State(GLenum face, GLuint mask) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void StencilMask_State(GLuint mask) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void StencilFuncSeparate_State(GLenum face, GLenum func, GLint ref, GLuint mask) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void StencilFunc_State(GLenum func, GLint ref, GLuint mask) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void Scissor_State(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
if (width < 0 || height < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "Scissor_State",
|
||||
"Width abd height must be non-negative."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetScissorBox(IntVec4(x, y, width, height));
|
||||
}
|
||||
|
||||
void SampleCoverage_State(GLfloat value, GLboolean invert) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void PolygonOffset_State(GLfloat factor, GLfloat units) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void PolygonMode_State(GLenum face, GLenum mode) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void PointSize_State(GLfloat size) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void PointParameterf_State(GLenum pname, GLfloat param) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void PointParameteri_State(GLenum pname, GLint param) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void PixelStorei_State(GLenum pname, GLint param) {
|
||||
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), param);
|
||||
PixelStoreParam pixelStoreParam = MG_Util::ConvertGLEnumToPixelStoreParam(pname);
|
||||
if (pixelStoreParam == PixelStoreParam::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "PixelStorei_State",
|
||||
"Pixel store param enum " +
|
||||
MG_Util::ConvertPixelStoreParamToString(pixelStoreParam) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(pname) + ") is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetPixelStoreParam(pixelStoreParam, param);
|
||||
}
|
||||
|
||||
void LogicOp_State(GLenum opcode) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void LineWidth_State(GLfloat width) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
GLboolean IsEnabledi_State(GLenum target, GLuint index) {
|
||||
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
|
||||
if (capInput == CapabilityInput::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "IsEnabledi_State",
|
||||
"Capability enum " +
|
||||
MG_Util::ConvertCapabilityInputToString(capInput) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
return MG_State::pGLContext->IsCapabilityEnabledIndexed(capInput, index) ? GL_TRUE : GL_FALSE;
|
||||
}
|
||||
|
||||
GLboolean IsEnabled_State(GLenum cap) {
|
||||
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
|
||||
if (capInput == CapabilityInput::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "IsEnabled_State",
|
||||
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
||||
"(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported."));
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
return MG_State::pGLContext->IsCapabilityEnabled(capInput) ? GL_TRUE : GL_FALSE;
|
||||
}
|
||||
|
||||
void Hint_State(GLenum target, GLenum mode) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void FrontFace_State(GLenum mode) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void Enable_State(GLenum cap) {
|
||||
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
|
||||
if (capInput == CapabilityInput::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "Enable_State",
|
||||
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
||||
"(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetCapability(capInput, true);
|
||||
}
|
||||
|
||||
void Disable_State(GLenum cap) {
|
||||
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
|
||||
if (capInput == CapabilityInput::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "Disable_State",
|
||||
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
||||
"(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetCapability(capInput, false);
|
||||
}
|
||||
|
||||
void DepthRange_State(GLclampd near_val, GLclampd far_val) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void DepthMask_State(GLboolean flag) {
|
||||
MG_State::pGLContext->SetDepthMask(flag == GL_TRUE);
|
||||
}
|
||||
|
||||
void DepthFunc_State(GLenum func) {
|
||||
DepthTestFunc depthFunc = MG_Util::ConvertGLEnumToDepthTestFunc(func);
|
||||
if (depthFunc == DepthTestFunc::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DepthFunc_State",
|
||||
"Depth function enum " +
|
||||
MG_Util::ConvertDepthTestFuncToString(depthFunc) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(func) + ") is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetDepthFunc(depthFunc);
|
||||
}
|
||||
|
||||
void CullFace_State(GLenum mode) {
|
||||
CullFaceMode cullFaceMode = MG_Util::ConvertGLEnumToCullFaceMode(mode);
|
||||
if (cullFaceMode == CullFaceMode::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "CullFace_State",
|
||||
"Cull face mode enum " +
|
||||
MG_Util::ConvertCullFaceModeToString(cullFaceMode) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(mode) + ") is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetCullFaceMode(cullFaceMode);
|
||||
}
|
||||
|
||||
void ColorMask_State(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
|
||||
MG_State::pGLContext->SetColorMask(
|
||||
BoolVec4(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE));
|
||||
}
|
||||
|
||||
void ClampColor_State(GLenum target, GLenum clamp) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void BlendFuncSeparate_State(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {
|
||||
BlendFactor srcRGB = MG_Util::ConvertGLEnumToBlendFactor(sfactorRGB);
|
||||
BlendFactor dstRGB = MG_Util::ConvertGLEnumToBlendFactor(dfactorRGB);
|
||||
BlendFactor srcAlpha = MG_Util::ConvertGLEnumToBlendFactor(sfactorAlpha);
|
||||
BlendFactor dstAlpha = MG_Util::ConvertGLEnumToBlendFactor(dfactorAlpha);
|
||||
|
||||
if (srcRGB == BlendFactor::Unknown || dstRGB == BlendFactor::Unknown || srcAlpha == BlendFactor::Unknown ||
|
||||
dstAlpha == BlendFactor::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "BlendFuncSeparate_State",
|
||||
"One of the blend factor enums is not supported: srcRGB " +
|
||||
MG_Util::ConvertBlendFactorToString(srcRGB) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(sfactorRGB) + "), dstRGB " +
|
||||
MG_Util::ConvertBlendFactorToString(dstRGB) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(dfactorRGB) + "), srcAlpha " +
|
||||
MG_Util::ConvertBlendFactorToString(srcAlpha) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(sfactorAlpha) + "), dstAlpha " +
|
||||
MG_Util::ConvertBlendFactorToString(dstAlpha) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(dfactorAlpha) + ")."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
|
||||
void BlendFunc_State(GLenum sfactor, GLenum dfactor) {
|
||||
BlendFuncSeparate_State(sfactor, dfactor, sfactor, dfactor);
|
||||
}
|
||||
|
||||
void BlendEquation_State(GLenum mode) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void BlendColor_State(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void ClearStencil_State(GLint s) {
|
||||
MG_State::pGLContext->SetClearStencil(static_cast<Int>(s));
|
||||
}
|
||||
|
||||
void ClearDepth_State(GLclampd depth) {
|
||||
MG_State::pGLContext->SetClearDepth(static_cast<Float>(depth));
|
||||
}
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
void Viewport_State(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
if (width < 0 || height < 0) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Viewport_State",
|
||||
"Width abd height must be non-negative."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetViewport(IntVec4(x, y, width, height));
|
||||
}
|
||||
|
||||
void StencilOpSeparate_State(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void StencilOp_State(GLenum fail, GLenum zfail, GLenum zpass) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void StencilMaskSeparate_State(GLenum face, GLuint mask) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void StencilMask_State(GLuint mask) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void StencilFuncSeparate_State(GLenum face, GLenum func, GLint ref, GLuint mask) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void StencilFunc_State(GLenum func, GLint ref, GLuint mask) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void Scissor_State(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
if (width < 0 || height < 0) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Scissor_State",
|
||||
"Width abd height must be non-negative."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetScissorBox(IntVec4(x, y, width, height));
|
||||
}
|
||||
|
||||
void SampleCoverage_State(GLfloat value, GLboolean invert) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void PolygonOffset_State(GLfloat factor, GLfloat units) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void PolygonMode_State(GLenum face, GLenum mode) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void PointSize_State(GLfloat size) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void PointParameterf_State(GLenum pname, GLfloat param) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void PointParameteri_State(GLenum pname, GLint param) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void PixelStorei_State(GLenum pname, GLint param) {
|
||||
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), param);
|
||||
PixelStoreParam pixelStoreParam = MG_Util::ConvertGLEnumToPixelStoreParam(pname);
|
||||
if (pixelStoreParam == PixelStoreParam::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "PixelStorei_State",
|
||||
"Pixel store param enum " +
|
||||
MG_Util::ConvertPixelStoreParamToString(pixelStoreParam) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(pname) + ") is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetPixelStoreParam(pixelStoreParam, param);
|
||||
}
|
||||
|
||||
void LogicOp_State(GLenum opcode) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void LineWidth_State(GLfloat width) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
GLboolean IsEnabledi_State(GLenum target, GLuint index) {
|
||||
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
|
||||
if (capInput == CapabilityInput::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "IsEnabledi_State",
|
||||
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
||||
"(" + MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
return MG_State::pGLContext->IsCapabilityEnabledIndexed(capInput, index) ? GL_TRUE : GL_FALSE;
|
||||
}
|
||||
|
||||
GLboolean IsEnabled_State(GLenum cap) {
|
||||
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
|
||||
if (capInput == CapabilityInput::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "IsEnabled_State",
|
||||
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
||||
"(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported."));
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
return MG_State::pGLContext->IsCapabilityEnabled(capInput) ? GL_TRUE : GL_FALSE;
|
||||
}
|
||||
|
||||
void Hint_State(GLenum target, GLenum mode) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void FrontFace_State(GLenum mode) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void Enable_State(GLenum cap) {
|
||||
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
|
||||
if (capInput == CapabilityInput::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Enable_State",
|
||||
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
||||
"(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetCapability(capInput, true);
|
||||
}
|
||||
|
||||
void Disable_State(GLenum cap) {
|
||||
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
|
||||
if (capInput == CapabilityInput::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Disable_State",
|
||||
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
||||
"(" + MG_Util::ConvertGLEnumToString(cap) + ") is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetCapability(capInput, false);
|
||||
}
|
||||
|
||||
void DepthRange_State(GLclampd near_val, GLclampd far_val) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void DepthMask_State(GLboolean flag) {
|
||||
MG_State::pGLContext->SetDepthMask(flag == GL_TRUE);
|
||||
}
|
||||
|
||||
void DepthFunc_State(GLenum func) {
|
||||
DepthTestFunc depthFunc = MG_Util::ConvertGLEnumToDepthTestFunc(func);
|
||||
if (depthFunc == DepthTestFunc::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DepthFunc_State",
|
||||
"Depth function enum " + MG_Util::ConvertDepthTestFuncToString(depthFunc) +
|
||||
"(" + MG_Util::ConvertGLEnumToString(func) + ") is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetDepthFunc(depthFunc);
|
||||
}
|
||||
|
||||
void CullFace_State(GLenum mode) {
|
||||
CullFaceMode cullFaceMode = MG_Util::ConvertGLEnumToCullFaceMode(mode);
|
||||
if (cullFaceMode == CullFaceMode::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CullFace_State",
|
||||
"Cull face mode enum " +
|
||||
MG_Util::ConvertCullFaceModeToString(cullFaceMode) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(mode) + ") is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetCullFaceMode(cullFaceMode);
|
||||
}
|
||||
|
||||
void ColorMask_State(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
|
||||
MG_State::pGLContext->SetColorMask(
|
||||
BoolVec4(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE));
|
||||
}
|
||||
|
||||
void ClampColor_State(GLenum target, GLenum clamp) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void BlendFuncSeparate_State(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {
|
||||
BlendFactor srcRGB = MG_Util::ConvertGLEnumToBlendFactor(sfactorRGB);
|
||||
BlendFactor dstRGB = MG_Util::ConvertGLEnumToBlendFactor(dfactorRGB);
|
||||
BlendFactor srcAlpha = MG_Util::ConvertGLEnumToBlendFactor(sfactorAlpha);
|
||||
BlendFactor dstAlpha = MG_Util::ConvertGLEnumToBlendFactor(dfactorAlpha);
|
||||
|
||||
if (srcRGB == BlendFactor::Unknown || dstRGB == BlendFactor::Unknown || srcAlpha == BlendFactor::Unknown ||
|
||||
dstAlpha == BlendFactor::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BlendFuncSeparate_State",
|
||||
"One of the blend factor enums is not supported: srcRGB " +
|
||||
MG_Util::ConvertBlendFactorToString(srcRGB) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(sfactorRGB) + "), dstRGB " +
|
||||
MG_Util::ConvertBlendFactorToString(dstRGB) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(dfactorRGB) + "), srcAlpha " +
|
||||
MG_Util::ConvertBlendFactorToString(srcAlpha) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(sfactorAlpha) + "), dstAlpha " +
|
||||
MG_Util::ConvertBlendFactorToString(dstAlpha) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(dfactorAlpha) + ")."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
|
||||
void BlendFunc_State(GLenum sfactor, GLenum dfactor) {
|
||||
BlendFuncSeparate_State(sfactor, dfactor, sfactor, dfactor);
|
||||
}
|
||||
|
||||
void BlendEquation_State(GLenum mode) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void BlendColor_State(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void ClearStencil_State(GLint s) {
|
||||
MG_State::pGLContext->SetClearStencil(static_cast<Int>(s));
|
||||
}
|
||||
|
||||
void ClearDepth_State(GLclampd depth) {
|
||||
MG_State::pGLContext->SetClearDepth(static_cast<Float>(depth));
|
||||
}
|
||||
|
||||
void ClearColor_State(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
MG_State::pGLContext->SetClearColor(FloatVec4(red, green, blue, alpha));
|
||||
}
|
||||
|
||||
void BlendFuncSeparatei_State(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
|
||||
if (buf >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "BlendFuncSeparatei_State",
|
||||
"Buffer index " + std::to_string(buf) + " is out of range. Max supported is " +
|
||||
std::to_string(MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS - 1) + "."));
|
||||
return;
|
||||
}
|
||||
|
||||
BlendFactor srcRGBM = MG_Util::ConvertGLEnumToBlendFactor(srcRGB);
|
||||
BlendFactor dstRGBM = MG_Util::ConvertGLEnumToBlendFactor(dstRGB);
|
||||
BlendFactor srcAlphaM = MG_Util::ConvertGLEnumToBlendFactor(srcAlpha);
|
||||
BlendFactor dstAlphaM = MG_Util::ConvertGLEnumToBlendFactor(dstAlpha);
|
||||
MG_State::pGLContext->SetBlendFuncIndexed(buf, srcRGBM, dstRGBM, srcAlphaM, dstAlphaM);
|
||||
}
|
||||
|
||||
void Disablei_State(GLenum target, GLuint index) {
|
||||
auto capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
|
||||
if (capInput == CapabilityInput::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Disablei_State",
|
||||
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
||||
"(" + MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetCapabilityIndexed(capInput, index, false);
|
||||
}
|
||||
|
||||
void Enablei_State(GLenum target, GLuint index) {
|
||||
auto capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
|
||||
if (capInput == CapabilityInput::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "Enablei_State",
|
||||
"Capability enum " + MG_Util::ConvertCapabilityInputToString(capInput) +
|
||||
"(" + MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetCapabilityIndexed(capInput, index, true);
|
||||
}
|
||||
|
||||
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
||||
void BlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
|
||||
BlendFuncSeparatei_State(buf, srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
|
||||
void Disablei(GLenum target, GLuint index) {
|
||||
Disablei_State(target, index);
|
||||
}
|
||||
|
||||
void Enablei(GLenum target, GLuint index) {
|
||||
Enablei_State(target, index);
|
||||
}
|
||||
|
||||
void BlendFunc(GLenum sfactor, GLenum dfactor) {
|
||||
BlendFunc_State(sfactor, dfactor);
|
||||
}
|
||||
|
||||
void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
Viewport_State(x, y, width, height);
|
||||
}
|
||||
|
||||
void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {
|
||||
StencilOpSeparate_State(face, sfail, dpfail, dppass);
|
||||
}
|
||||
|
||||
void StencilOp(GLenum fail, GLenum zfail, GLenum zpass) {
|
||||
StencilOp_State(fail, zfail, zpass);
|
||||
}
|
||||
|
||||
void StencilMaskSeparate(GLenum face, GLuint mask) {
|
||||
StencilMaskSeparate_State(face, mask);
|
||||
}
|
||||
|
||||
void StencilMask(GLuint mask) {
|
||||
StencilMask_State(mask);
|
||||
}
|
||||
|
||||
void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) {
|
||||
StencilFuncSeparate_State(face, func, ref, mask);
|
||||
}
|
||||
|
||||
void StencilFunc(GLenum func, GLint ref, GLuint mask) {
|
||||
StencilFunc_State(func, ref, mask);
|
||||
}
|
||||
|
||||
void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
Scissor_State(x, y, width, height);
|
||||
}
|
||||
|
||||
void SampleCoverage(GLfloat value, GLboolean invert) {
|
||||
SampleCoverage_State(value, invert);
|
||||
}
|
||||
|
||||
void PolygonOffset(GLfloat factor, GLfloat units) {
|
||||
PolygonOffset_State(factor, units);
|
||||
}
|
||||
|
||||
void PolygonMode(GLenum face, GLenum mode) {
|
||||
PolygonMode_State(face, mode);
|
||||
}
|
||||
|
||||
void PointSize(GLfloat size) {
|
||||
PointSize_State(size);
|
||||
}
|
||||
|
||||
void PointParameterf(GLenum pname, GLfloat param) {
|
||||
PointParameterf_State(pname, param);
|
||||
}
|
||||
|
||||
void PointParameteri(GLenum pname, GLint param) {
|
||||
PointParameteri_State(pname, param);
|
||||
}
|
||||
|
||||
void PixelStorei(GLenum pname, GLint param) {
|
||||
PixelStorei_State(pname, param);
|
||||
}
|
||||
|
||||
void LogicOp(GLenum opcode) {
|
||||
LogicOp_State(opcode);
|
||||
}
|
||||
|
||||
void ClearColor_State(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
MG_State::pGLContext->SetClearColor(FloatVec4(red, green, blue, alpha));
|
||||
}
|
||||
|
||||
void BlendFuncSeparatei_State(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
|
||||
if (buf >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "BlendFuncSeparatei_State",
|
||||
"Buffer index " + std::to_string(buf) + " is out of range. Max supported is " +
|
||||
std::to_string(MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS - 1) + "."));
|
||||
return;
|
||||
}
|
||||
|
||||
BlendFactor srcRGBM = MG_Util::ConvertGLEnumToBlendFactor(srcRGB);
|
||||
BlendFactor dstRGBM = MG_Util::ConvertGLEnumToBlendFactor(dstRGB);
|
||||
BlendFactor srcAlphaM = MG_Util::ConvertGLEnumToBlendFactor(srcAlpha);
|
||||
BlendFactor dstAlphaM = MG_Util::ConvertGLEnumToBlendFactor(dstAlpha);
|
||||
MG_State::pGLContext->SetBlendFuncIndexed(buf, srcRGBM, dstRGBM, srcAlphaM, dstAlphaM);
|
||||
}
|
||||
|
||||
void Disablei_State(GLenum target, GLuint index) {
|
||||
auto capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
|
||||
if (capInput == CapabilityInput::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "Disablei_State",
|
||||
"Capability enum " +
|
||||
MG_Util::ConvertCapabilityInputToString(capInput) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetCapabilityIndexed(capInput, index, false);
|
||||
}
|
||||
|
||||
void Enablei_State(GLenum target, GLuint index) {
|
||||
auto capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
|
||||
if (capInput == CapabilityInput::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "Enablei_State",
|
||||
"Capability enum " +
|
||||
MG_Util::ConvertCapabilityInputToString(capInput) + "(" +
|
||||
MG_Util::ConvertGLEnumToString(target) + ") is not supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
MG_State::pGLContext->SetCapabilityIndexed(capInput, index, true);
|
||||
}
|
||||
|
||||
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
||||
void BlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
|
||||
BlendFuncSeparatei_State(buf, srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
|
||||
void Disablei(GLenum target, GLuint index) {
|
||||
Disablei_State(target, index);
|
||||
}
|
||||
|
||||
void Enablei(GLenum target, GLuint index) {
|
||||
Enablei_State(target, index);
|
||||
}
|
||||
|
||||
void BlendFunc(GLenum sfactor, GLenum dfactor) {
|
||||
BlendFunc_State(sfactor, dfactor);
|
||||
}
|
||||
|
||||
void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
Viewport_State(x, y, width, height);
|
||||
}
|
||||
|
||||
void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {
|
||||
StencilOpSeparate_State(face, sfail, dpfail, dppass);
|
||||
}
|
||||
|
||||
void StencilOp(GLenum fail, GLenum zfail, GLenum zpass) {
|
||||
StencilOp_State(fail, zfail, zpass);
|
||||
}
|
||||
|
||||
void StencilMaskSeparate(GLenum face, GLuint mask) {
|
||||
StencilMaskSeparate_State(face, mask);
|
||||
}
|
||||
|
||||
void StencilMask(GLuint mask) {
|
||||
StencilMask_State(mask);
|
||||
}
|
||||
|
||||
void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) {
|
||||
StencilFuncSeparate_State(face, func, ref, mask);
|
||||
}
|
||||
|
||||
void StencilFunc(GLenum func, GLint ref, GLuint mask) {
|
||||
StencilFunc_State(func, ref, mask);
|
||||
}
|
||||
|
||||
void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
Scissor_State(x, y, width, height);
|
||||
}
|
||||
|
||||
void SampleCoverage(GLfloat value, GLboolean invert) {
|
||||
SampleCoverage_State(value, invert);
|
||||
}
|
||||
|
||||
void PolygonOffset(GLfloat factor, GLfloat units) {
|
||||
PolygonOffset_State(factor, units);
|
||||
}
|
||||
void LineWidth(GLfloat width) {
|
||||
LineWidth_State(width);
|
||||
}
|
||||
|
||||
GLboolean IsEnabledi(GLenum target, GLuint index) {
|
||||
return IsEnabledi_State(target, index);
|
||||
}
|
||||
|
||||
GLboolean IsEnabled(GLenum cap) {
|
||||
return IsEnabled_State(cap);
|
||||
}
|
||||
|
||||
void PolygonMode(GLenum face, GLenum mode) {
|
||||
PolygonMode_State(face, mode);
|
||||
}
|
||||
void Hint(GLenum target, GLenum mode) {
|
||||
Hint_State(target, mode);
|
||||
}
|
||||
|
||||
void PointSize(GLfloat size) {
|
||||
PointSize_State(size);
|
||||
}
|
||||
void FrontFace(GLenum mode) {
|
||||
FrontFace_State(mode);
|
||||
}
|
||||
|
||||
void Enable(GLenum cap) {
|
||||
Enable_State(cap);
|
||||
}
|
||||
|
||||
void PointParameterf(GLenum pname, GLfloat param) {
|
||||
PointParameterf_State(pname, param);
|
||||
}
|
||||
void Disable(GLenum cap) {
|
||||
Disable_State(cap);
|
||||
}
|
||||
|
||||
void PointParameteri(GLenum pname, GLint param) {
|
||||
PointParameteri_State(pname, param);
|
||||
}
|
||||
void DepthRange(GLclampd near_val, GLclampd far_val) {
|
||||
DepthRange_State(near_val, far_val);
|
||||
}
|
||||
|
||||
void PixelStorei(GLenum pname, GLint param) {
|
||||
PixelStorei_State(pname, param);
|
||||
}
|
||||
|
||||
void LogicOp(GLenum opcode) {
|
||||
LogicOp_State(opcode);
|
||||
}
|
||||
|
||||
void LineWidth(GLfloat width) {
|
||||
LineWidth_State(width);
|
||||
}
|
||||
void DepthMask(GLboolean flag) {
|
||||
DepthMask_State(flag);
|
||||
}
|
||||
|
||||
GLboolean IsEnabledi(GLenum target, GLuint index) {
|
||||
return IsEnabledi_State(target, index);
|
||||
}
|
||||
void DepthFunc(GLenum func) {
|
||||
DepthFunc_State(func);
|
||||
}
|
||||
|
||||
GLboolean IsEnabled(GLenum cap) {
|
||||
return IsEnabled_State(cap);
|
||||
}
|
||||
void CullFace(GLenum mode) {
|
||||
CullFace_State(mode);
|
||||
}
|
||||
|
||||
void Hint(GLenum target, GLenum mode) {
|
||||
Hint_State(target, mode);
|
||||
}
|
||||
void ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
|
||||
ColorMask_State(red, green, blue, alpha);
|
||||
}
|
||||
|
||||
void FrontFace(GLenum mode) {
|
||||
FrontFace_State(mode);
|
||||
}
|
||||
void ClampColor(GLenum target, GLenum clamp) {
|
||||
ClampColor_State(target, clamp);
|
||||
}
|
||||
|
||||
void Enable(GLenum cap) {
|
||||
Enable_State(cap);
|
||||
}
|
||||
void BlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {
|
||||
BlendFuncSeparate_State(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
|
||||
}
|
||||
|
||||
void Disable(GLenum cap) {
|
||||
Disable_State(cap);
|
||||
}
|
||||
void BlendEquation(GLenum mode) {
|
||||
BlendEquation_State(mode);
|
||||
}
|
||||
|
||||
void DepthRange(GLclampd near_val, GLclampd far_val) {
|
||||
DepthRange_State(near_val, far_val);
|
||||
}
|
||||
void BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
BlendColor_State(red, green, blue, alpha);
|
||||
}
|
||||
|
||||
void DepthMask(GLboolean flag) {
|
||||
DepthMask_State(flag);
|
||||
}
|
||||
void ClearStencil(GLint s) {
|
||||
ClearStencil_State(s);
|
||||
}
|
||||
|
||||
void DepthFunc(GLenum func) {
|
||||
DepthFunc_State(func);
|
||||
}
|
||||
void ClearDepth(GLclampd depth) {
|
||||
ClearDepth_State(depth);
|
||||
}
|
||||
|
||||
void CullFace(GLenum mode) {
|
||||
CullFace_State(mode);
|
||||
}
|
||||
|
||||
void ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
|
||||
ColorMask_State(red, green, blue, alpha);
|
||||
}
|
||||
|
||||
void ClampColor(GLenum target, GLenum clamp) {
|
||||
ClampColor_State(target, clamp);
|
||||
}
|
||||
|
||||
void BlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {
|
||||
BlendFuncSeparate_State(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
|
||||
}
|
||||
|
||||
void BlendEquation(GLenum mode) {
|
||||
BlendEquation_State(mode);
|
||||
}
|
||||
|
||||
void BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
BlendColor_State(red, green, blue, alpha);
|
||||
}
|
||||
|
||||
void ClearStencil(GLint s) {
|
||||
ClearStencil_State(s);
|
||||
}
|
||||
|
||||
void ClearDepth(GLclampd depth) {
|
||||
ClearDepth_State(depth);
|
||||
}
|
||||
|
||||
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
ClearColor_State(red, green, blue, alpha);
|
||||
}
|
||||
} // namespace MG_Impl::GLImpl
|
||||
} // namespace MobileGL
|
||||
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
ClearColor_State(red, green, blue, alpha);
|
||||
}
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -9,47 +9,45 @@
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void BlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
|
||||
void Disablei(GLenum target, GLuint index);
|
||||
void Enablei(GLenum target, GLuint index);
|
||||
void BlendFunc(GLenum sfactor, GLenum dfactor);
|
||||
void Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
|
||||
void StencilOp(GLenum fail, GLenum zfail, GLenum zpass);
|
||||
void StencilMaskSeparate(GLenum face, GLuint mask);
|
||||
void StencilMask(GLuint mask);
|
||||
void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
|
||||
void StencilFunc(GLenum func, GLint ref, GLuint mask);
|
||||
void Scissor(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
void SampleCoverage(GLfloat value, GLboolean invert);
|
||||
void PolygonOffset(GLfloat factor, GLfloat units);
|
||||
void PolygonMode(GLenum face, GLenum mode);
|
||||
void PointSize(GLfloat size);
|
||||
void PointParameterf(GLenum pname, GLfloat param);
|
||||
void PointParameteri(GLenum pname, GLint param);
|
||||
void PixelStorei(GLenum pname, GLint param);
|
||||
void LogicOp(GLenum opcode);
|
||||
void LineWidth(GLfloat width);
|
||||
GLboolean IsEnabledi(GLenum target, GLuint index);
|
||||
GLboolean IsEnabled(GLenum cap);
|
||||
void Hint(GLenum target, GLenum mode);
|
||||
void FrontFace(GLenum mode);
|
||||
void Enable(GLenum cap);
|
||||
void Disable(GLenum cap);
|
||||
void DepthRange(GLclampd near_val, GLclampd far_val);
|
||||
void DepthMask(GLboolean flag);
|
||||
void DepthFunc(GLenum func);
|
||||
void CullFace(GLenum mode);
|
||||
void ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
|
||||
void ClampColor(GLenum target, GLenum clamp);
|
||||
void BlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
|
||||
void BlendEquation(GLenum mode);
|
||||
void BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
void ClearStencil(GLint s);
|
||||
void ClearDepth(GLclampd depth);
|
||||
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
} // namespace MG_Impl::GLImpl
|
||||
} // namespace MobileGL
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void BlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
|
||||
void Disablei(GLenum target, GLuint index);
|
||||
void Enablei(GLenum target, GLuint index);
|
||||
void BlendFunc(GLenum sfactor, GLenum dfactor);
|
||||
void Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
|
||||
void StencilOp(GLenum fail, GLenum zfail, GLenum zpass);
|
||||
void StencilMaskSeparate(GLenum face, GLuint mask);
|
||||
void StencilMask(GLuint mask);
|
||||
void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
|
||||
void StencilFunc(GLenum func, GLint ref, GLuint mask);
|
||||
void Scissor(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
void SampleCoverage(GLfloat value, GLboolean invert);
|
||||
void PolygonOffset(GLfloat factor, GLfloat units);
|
||||
void PolygonMode(GLenum face, GLenum mode);
|
||||
void PointSize(GLfloat size);
|
||||
void PointParameterf(GLenum pname, GLfloat param);
|
||||
void PointParameteri(GLenum pname, GLint param);
|
||||
void PixelStorei(GLenum pname, GLint param);
|
||||
void LogicOp(GLenum opcode);
|
||||
void LineWidth(GLfloat width);
|
||||
GLboolean IsEnabledi(GLenum target, GLuint index);
|
||||
GLboolean IsEnabled(GLenum cap);
|
||||
void Hint(GLenum target, GLenum mode);
|
||||
void FrontFace(GLenum mode);
|
||||
void Enable(GLenum cap);
|
||||
void Disable(GLenum cap);
|
||||
void DepthRange(GLclampd near_val, GLclampd far_val);
|
||||
void DepthMask(GLboolean flag);
|
||||
void DepthFunc(GLenum func);
|
||||
void CullFace(GLenum mode);
|
||||
void ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
|
||||
void ClampColor(GLenum target, GLenum clamp);
|
||||
void BlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
|
||||
void BlendEquation(GLenum mode);
|
||||
void BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
void ClearStencil(GLint s);
|
||||
void ClearDepth(GLclampd depth);
|
||||
void ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -12,254 +12,258 @@
|
||||
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Impl::GLImpl {
|
||||
void SetSamplerParam_State(GLuint sampler, GLenum pname, const void* param, bool isFloat, bool isInteger) {
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
void SetSamplerParam_State(GLuint sampler, GLenum pname, const void* param, bool isFloat, bool isInteger) {
|
||||
if (!SamplerImpl::ValidateSamplerName(sampler)) return;
|
||||
|
||||
Bool doesSamplerObjectCreated = MG_State::pGLContext->ValidateSamplerObject(sampler);
|
||||
if (!doesSamplerObjectCreated) {
|
||||
// Create one for compatibility
|
||||
MG_State::pGLContext->CreateSamplerObject(sampler);
|
||||
}
|
||||
auto& samplerObj = MG_State::pGLContext->GetSamplerObject(sampler);
|
||||
if (!SamplerImpl::ValidateSamplerObject(sampler)) return;
|
||||
|
||||
using namespace MG_Util;
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_WRAP_S:
|
||||
samplerObj->SetWrapS(MG_Util::ConvertGLEnumToSamplerWrapMode(*(const GLint*)param));
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_T:
|
||||
samplerObj->SetWrapT(MG_Util::ConvertGLEnumToSamplerWrapMode(*(const GLint*)param));
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_R:
|
||||
samplerObj->SetWrapR(MG_Util::ConvertGLEnumToSamplerWrapMode(*(const GLint*)param));
|
||||
break;
|
||||
case GL_TEXTURE_MIN_FILTER:
|
||||
samplerObj->SetMinFilter(MG_Util::ConvertGLEnumToSamplerFilterMode(*(const GLint*)param));
|
||||
samplerObj->SetMipmapMode(MG_Util::ConvertGLEnumToSamplerMipmapMode(*(const GLint*)param));
|
||||
break;
|
||||
case GL_TEXTURE_MAG_FILTER:
|
||||
samplerObj->SetMagFilter(MG_Util::ConvertGLEnumToSamplerFilterMode(*(const GLint*)param));
|
||||
break;
|
||||
case GL_TEXTURE_MIN_LOD:
|
||||
samplerObj->SetLodRange(*(const GLfloat*)param, samplerObj->GetMaxLod());
|
||||
break;
|
||||
case GL_TEXTURE_MAX_LOD:
|
||||
samplerObj->SetLodRange(samplerObj->GetMinLod(), *(const GLfloat*)param);
|
||||
break;
|
||||
case GL_TEXTURE_LOD_BIAS:
|
||||
samplerObj->SetLodBias(*(const GLfloat*)param);
|
||||
break;
|
||||
case GL_TEXTURE_COMPARE_MODE:
|
||||
samplerObj->SetCompareMode(MG_Util::ConvertGLEnumToSamplerCompareMode(*(const GLint*)param));
|
||||
break;
|
||||
case GL_TEXTURE_COMPARE_FUNC:
|
||||
samplerObj->SetSamplerCompareFunc(MG_Util::ConvertGLEnumToSamplerCompareFunc(*(const GLint*)param));
|
||||
break;
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "SetSamplerParam_State",
|
||||
"Invalid pname for sampler parameter"));
|
||||
}
|
||||
}
|
||||
|
||||
void GetSamplerParam_State(GLuint sampler, GLenum pname, void* params, bool isFloat, bool isInteger) {
|
||||
if (!SamplerImpl::ValidateSamplerName(sampler)) return;
|
||||
|
||||
Bool doesSamplerObjectCreated = MG_State::pGLContext->ValidateSamplerObject(sampler);
|
||||
if (!doesSamplerObjectCreated) {
|
||||
// Create one for compatibility
|
||||
MG_State::pGLContext->CreateSamplerObject(sampler);
|
||||
}
|
||||
auto& samplerObj = MG_State::pGLContext->GetSamplerObject(sampler);
|
||||
if (!SamplerImpl::ValidateSamplerObject(sampler)) return;
|
||||
|
||||
using namespace MG_Util;
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_WRAP_S:
|
||||
*(GLuint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapS());
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_T:
|
||||
*(GLuint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapT());
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_R:
|
||||
*(GLuint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapR());
|
||||
break;
|
||||
case GL_TEXTURE_MIN_FILTER:
|
||||
*(GLuint*)params =
|
||||
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerObj->GetMinFilter(), samplerObj->GetMipmapMode());
|
||||
break;
|
||||
case GL_TEXTURE_MAG_FILTER:
|
||||
*(GLuint*)params =
|
||||
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerObj->GetMagFilter(), SamplerMipmapMode::None);
|
||||
break;
|
||||
case GL_TEXTURE_MIN_LOD:
|
||||
*(GLfloat*)params = samplerObj->GetMinLod();
|
||||
break;
|
||||
case GL_TEXTURE_MAX_LOD:
|
||||
*(GLfloat*)params = samplerObj->GetMaxLod();
|
||||
break;
|
||||
case GL_TEXTURE_LOD_BIAS:
|
||||
*(GLfloat*)params = samplerObj->GetLodBias();
|
||||
break;
|
||||
case GL_TEXTURE_COMPARE_MODE:
|
||||
*(GLuint*)params = MG_Util::ConvertSamplerCompareModeToGLEnum(samplerObj->GetCompareMode());
|
||||
break;
|
||||
case GL_TEXTURE_COMPARE_FUNC:
|
||||
*(GLuint*)params = MG_Util::ConvertSamplerCompareFuncToGLEnum(samplerObj->GetSamplerCompareFunc());
|
||||
break;
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetSamplerParam_State",
|
||||
"Invalid pname for sampler parameter"));
|
||||
}
|
||||
}
|
||||
|
||||
GLboolean IsSampler_State(GLuint sampler) {
|
||||
return MG_State::pGLContext->ValidateSamplerObject(sampler) ? GL_TRUE : GL_FALSE;
|
||||
}
|
||||
|
||||
// migrate below functions without "_State" into this section
|
||||
void GenSamplers_State(GLsizei count, GLuint* samplers) {
|
||||
if (count < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenSamplers", "count must be non-negative"));
|
||||
return;
|
||||
}
|
||||
|
||||
static thread_local Vector<GLuint> names;
|
||||
MG_State::pGLContext->GenSamplerNames(count, names);
|
||||
Memcpy(samplers, names.data(), count * sizeof(GLuint));
|
||||
}
|
||||
|
||||
void DeleteSamplers_State(GLsizei count, const GLuint* samplers) {
|
||||
if (count < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteSamplers", "count must be non-negative"));
|
||||
return;
|
||||
}
|
||||
|
||||
for (GLsizei i = 0; i < count; ++i) {
|
||||
if (samplers[i] != 0) {
|
||||
MG_State::pGLContext->MarkSamplerObjectForDeletion(samplers[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CreateSamplers_State(GLsizei n, GLuint* samplers) {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenSamplers", "count must be non-negative"));
|
||||
return;
|
||||
}
|
||||
|
||||
static thread_local Vector<GLuint> names;
|
||||
MG_State::pGLContext->GenSamplerNames(n, names);
|
||||
Memcpy(samplers, names.data(), n * sizeof(GLuint));
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
samplers[i] = names[i];
|
||||
MG_State::pGLContext->CreateSamplerObject(names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void BindSampler_State(GLuint unit, GLuint sampler) {
|
||||
if (unit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BindSampler", "texture unit out of range"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject((Int)unit);
|
||||
if (sampler == 0) {
|
||||
textureUnit.SetSamplerObject(nullptr);
|
||||
} else {
|
||||
if (!SamplerImpl::ValidateSamplerName(sampler)) return;
|
||||
|
||||
auto samplerObj = MG_State::pGLContext->GetSamplerObject(sampler);
|
||||
if (!samplerObj) {
|
||||
samplerObj = MG_State::pGLContext->CreateSamplerObject(sampler); // for compatibility
|
||||
Bool doesSamplerObjectCreated = MG_State::pGLContext->ValidateSamplerObject(sampler);
|
||||
if (!doesSamplerObjectCreated) {
|
||||
MG_State::pGLContext->CreateSamplerObject(sampler);
|
||||
}
|
||||
if (!SamplerImpl::ValidateSamplerObject(sampler)) return;
|
||||
auto& samplerObject = MG_State::pGLContext->GetSamplerObject(sampler);
|
||||
|
||||
using namespace MG_Util;
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_WRAP_S:
|
||||
samplerObj->SetWrapS(MG_Util::ConvertGLEnumToSamplerWrapMode(*(const GLint*)param));
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_T:
|
||||
samplerObj->SetWrapT(MG_Util::ConvertGLEnumToSamplerWrapMode(*(const GLint*)param));
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_R:
|
||||
samplerObj->SetWrapR(MG_Util::ConvertGLEnumToSamplerWrapMode(*(const GLint*)param));
|
||||
break;
|
||||
case GL_TEXTURE_MIN_FILTER:
|
||||
samplerObj->SetMinFilter(MG_Util::ConvertGLEnumToSamplerFilterMode(*(const GLint*)param));
|
||||
samplerObj->SetMipmapMode(MG_Util::ConvertGLEnumToSamplerMipmapMode(*(const GLint*)param));
|
||||
break;
|
||||
case GL_TEXTURE_MAG_FILTER:
|
||||
samplerObj->SetMagFilter(MG_Util::ConvertGLEnumToSamplerFilterMode(*(const GLint*)param));
|
||||
break;
|
||||
case GL_TEXTURE_MIN_LOD:
|
||||
samplerObj->SetLodRange(*(const GLfloat*)param, samplerObj->GetMaxLod());
|
||||
break;
|
||||
case GL_TEXTURE_MAX_LOD:
|
||||
samplerObj->SetLodRange(samplerObj->GetMinLod(), *(const GLfloat*)param);
|
||||
break;
|
||||
case GL_TEXTURE_LOD_BIAS:
|
||||
samplerObj->SetLodBias(*(const GLfloat*)param);
|
||||
break;
|
||||
case GL_TEXTURE_COMPARE_MODE:
|
||||
samplerObj->SetCompareMode(MG_Util::ConvertGLEnumToSamplerCompareMode(*(const GLint*)param));
|
||||
break;
|
||||
case GL_TEXTURE_COMPARE_FUNC:
|
||||
samplerObj->SetSamplerCompareFunc(MG_Util::ConvertGLEnumToSamplerCompareFunc(*(const GLint*)param));
|
||||
break;
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "SetSamplerParam_State",
|
||||
"Invalid pname for sampler parameter"));
|
||||
}
|
||||
textureUnit.SetSamplerObject(MG_State::pGLContext->GetSamplerObject(sampler));
|
||||
}
|
||||
}
|
||||
|
||||
void BindSamplers_State(GLuint first, GLsizei count, const GLuint* samplers) {
|
||||
if (count < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BindSamplers", "count must be non-negative"));
|
||||
return;
|
||||
}
|
||||
|
||||
void GetSamplerParam_State(GLuint sampler, GLenum pname, void* params, bool isFloat, bool isInteger) {
|
||||
if (!SamplerImpl::ValidateSamplerName(sampler)) return;
|
||||
|
||||
auto samplerObj = MG_State::pGLContext->GetSamplerObject(sampler);
|
||||
if (!samplerObj) {
|
||||
samplerObj = MG_State::pGLContext->CreateSamplerObject(sampler); // for compatibility
|
||||
}
|
||||
if (!SamplerImpl::ValidateSamplerObject(sampler)) return;
|
||||
|
||||
using namespace MG_Util;
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_WRAP_S:
|
||||
*(GLint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapS());
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_T:
|
||||
*(GLint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapT());
|
||||
break;
|
||||
case GL_TEXTURE_WRAP_R:
|
||||
*(GLint*)params = MG_Util::ConvertSamplerWrapModeToGLEnum(samplerObj->GetWrapR());
|
||||
break;
|
||||
case GL_TEXTURE_MIN_FILTER:
|
||||
*(GLint*)params =
|
||||
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerObj->GetMinFilter(), samplerObj->GetMipmapMode());
|
||||
break;
|
||||
case GL_TEXTURE_MAG_FILTER:
|
||||
*(GLint*)params =
|
||||
MG_Util::ConvertSamplerFilterModeToGLEnum(samplerObj->GetMagFilter(), SamplerMipmapMode::None);
|
||||
break;
|
||||
case GL_TEXTURE_MIN_LOD:
|
||||
*(GLfloat*)params = samplerObj->GetMinLod();
|
||||
break;
|
||||
case GL_TEXTURE_MAX_LOD:
|
||||
*(GLfloat*)params = samplerObj->GetMaxLod();
|
||||
break;
|
||||
case GL_TEXTURE_LOD_BIAS:
|
||||
*(GLfloat*)params = samplerObj->GetLodBias();
|
||||
break;
|
||||
case GL_TEXTURE_COMPARE_MODE:
|
||||
*(GLint*)params = MG_Util::ConvertSamplerCompareModeToGLEnum(samplerObj->GetCompareMode());
|
||||
break;
|
||||
case GL_TEXTURE_COMPARE_FUNC:
|
||||
*(GLint*)params = MG_Util::ConvertSamplerCompareFuncToGLEnum(samplerObj->GetSamplerCompareFunc());
|
||||
break;
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GetSamplerParam_State",
|
||||
"Invalid pname for sampler parameter"));
|
||||
}
|
||||
for (GLsizei i = 0; i < count; ++i) {
|
||||
BindSampler_State(first + i, samplers ? samplers[i] : 0);
|
||||
}
|
||||
}
|
||||
|
||||
GLboolean IsSampler_State(GLuint sampler) {
|
||||
return MG_State::pGLContext->ValidateSamplerObject(sampler) ? GL_TRUE : GL_FALSE;
|
||||
}
|
||||
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
||||
void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params) {
|
||||
GetSamplerParam_State(sampler, pname, params, false, false);
|
||||
}
|
||||
|
||||
// migrate below functions without "_State" into this section
|
||||
void GenSamplers_State(GLsizei count, GLuint* samplers) {
|
||||
if (count < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GenSamplers", "count must be non-negative"));
|
||||
return;
|
||||
}
|
||||
void SamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint* param) {
|
||||
SetSamplerParam_State(sampler, pname, param, false, true);
|
||||
}
|
||||
|
||||
auto names = MG_State::pGLContext->GenSamplerNames(count);
|
||||
for (GLsizei i = 0; i < count; ++i) {
|
||||
samplers[i] = names[i];
|
||||
}
|
||||
}
|
||||
void SamplerParameterIiv(GLuint sampler, GLenum pname, const GLint* param) {
|
||||
SetSamplerParam_State(sampler, pname, param, false, true);
|
||||
}
|
||||
|
||||
void DeleteSamplers_State(GLsizei count, const GLuint* samplers) {
|
||||
if (count < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteSamplers", "count must be non-negative"));
|
||||
return;
|
||||
}
|
||||
void SamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param) {
|
||||
SetSamplerParam_State(sampler, pname, param, false, false);
|
||||
}
|
||||
|
||||
for (GLsizei i = 0; i < count; ++i) {
|
||||
if (samplers[i] != 0) {
|
||||
MG_State::pGLContext->MarkSamplerObjectForDeletion(samplers[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
void SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param) {
|
||||
SetSamplerParam_State(sampler, pname, param, true, false);
|
||||
}
|
||||
|
||||
void CreateSamplers_State(GLsizei n, GLuint* samplers) {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GenSamplers", "count must be non-negative"));
|
||||
return;
|
||||
}
|
||||
void SamplerParameteri(GLuint sampler, GLenum pname, GLint param) {
|
||||
SamplerParameteriv(sampler, pname, ¶m);
|
||||
}
|
||||
|
||||
auto names = MG_State::pGLContext->GenSamplerNames(n);
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
samplers[i] = names[i];
|
||||
MG_State::pGLContext->CreateSamplerObject(names[i]);
|
||||
}
|
||||
}
|
||||
void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) {
|
||||
SamplerParameterfv(sampler, pname, ¶m);
|
||||
}
|
||||
|
||||
void BindSampler_State(GLuint unit, GLuint sampler) {
|
||||
if (unit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "BindSampler", "texture unit out of range"));
|
||||
return;
|
||||
}
|
||||
GLboolean IsSampler(GLuint sampler) {
|
||||
return IsSampler_State(sampler);
|
||||
}
|
||||
|
||||
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
|
||||
if (sampler == 0) {
|
||||
textureUnit.SetSamplerObject(nullptr);
|
||||
} else {
|
||||
if (!SamplerImpl::ValidateSamplerName(sampler)) return;
|
||||
auto samplerObject = MG_State::pGLContext->GetSamplerObject(sampler);
|
||||
if (!samplerObject) {
|
||||
samplerObject = MG_State::pGLContext->CreateSamplerObject(sampler);
|
||||
}
|
||||
void GetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint* params) {
|
||||
GetSamplerParam_State(sampler, pname, params, false, true);
|
||||
}
|
||||
|
||||
textureUnit.SetSamplerObject(MG_State::pGLContext->GetSamplerObject(sampler));
|
||||
}
|
||||
}
|
||||
void GetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint* params) {
|
||||
GetSamplerParam_State(sampler, pname, params, false, true);
|
||||
}
|
||||
|
||||
void BindSamplers_State(GLuint first, GLsizei count, const GLuint* samplers) {
|
||||
if (count < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "BindSamplers", "count must be non-negative"));
|
||||
return;
|
||||
}
|
||||
void GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params) {
|
||||
GetSamplerParam_State(sampler, pname, params, true, false);
|
||||
}
|
||||
|
||||
for (GLsizei i = 0; i < count; ++i) {
|
||||
BindSampler_State(first + i, samplers ? samplers[i] : 0);
|
||||
}
|
||||
}
|
||||
void GenSamplers(GLsizei count, GLuint* samplers) {
|
||||
GenSamplers_State(count, samplers);
|
||||
}
|
||||
|
||||
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
||||
void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params) {
|
||||
GetSamplerParam_State(sampler, pname, params, false, false);
|
||||
}
|
||||
void DeleteSamplers(GLsizei count, const GLuint* samplers) {
|
||||
DeleteSamplers_State(count, samplers);
|
||||
}
|
||||
|
||||
void SamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint* param) {
|
||||
SetSamplerParam_State(sampler, pname, param, false, true);
|
||||
}
|
||||
void CreateSamplers(GLsizei n, GLuint* samplers) {
|
||||
CreateSamplers_State(n, samplers);
|
||||
}
|
||||
|
||||
void SamplerParameterIiv(GLuint sampler, GLenum pname, const GLint* param) {
|
||||
SetSamplerParam_State(sampler, pname, param, false, true);
|
||||
}
|
||||
void BindSamplers(GLuint first, GLsizei count, const GLuint* samplers) {
|
||||
BindSamplers_State(first, count, samplers);
|
||||
}
|
||||
|
||||
void SamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param) {
|
||||
SetSamplerParam_State(sampler, pname, param, false, false);
|
||||
}
|
||||
|
||||
void SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param) {
|
||||
SetSamplerParam_State(sampler, pname, param, true, false);
|
||||
}
|
||||
|
||||
void SamplerParameteri(GLuint sampler, GLenum pname, GLint param) {
|
||||
SamplerParameteriv(sampler, pname, ¶m);
|
||||
}
|
||||
|
||||
void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) {
|
||||
SamplerParameterfv(sampler, pname, ¶m);
|
||||
}
|
||||
|
||||
GLboolean IsSampler(GLuint sampler) {
|
||||
return IsSampler_State(sampler);
|
||||
}
|
||||
|
||||
void GetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint* params) {
|
||||
GetSamplerParam_State(sampler, pname, params, false, true);
|
||||
}
|
||||
|
||||
void GetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint* params) {
|
||||
GetSamplerParam_State(sampler, pname, params, false, true);
|
||||
}
|
||||
|
||||
void GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params) {
|
||||
GetSamplerParam_State(sampler, pname, params, true, false);
|
||||
}
|
||||
|
||||
void GenSamplers(GLsizei count, GLuint* samplers) {
|
||||
GenSamplers_State(count, samplers);
|
||||
}
|
||||
|
||||
void DeleteSamplers(GLsizei count, const GLuint* samplers) {
|
||||
DeleteSamplers_State(count, samplers);
|
||||
}
|
||||
|
||||
void CreateSamplers(GLsizei n, GLuint* samplers) {
|
||||
CreateSamplers_State(n, samplers);
|
||||
}
|
||||
|
||||
void BindSamplers(GLuint first, GLsizei count, const GLuint* samplers) {
|
||||
BindSamplers_State(first, count, samplers);
|
||||
}
|
||||
|
||||
void BindSampler(GLuint unit, GLuint sampler) {
|
||||
BindSampler_State(unit, sampler);
|
||||
}
|
||||
} // namespace MG_Impl::GLImpl
|
||||
} // namespace MobileGL
|
||||
void BindSampler(GLuint unit, GLuint sampler) {
|
||||
BindSampler_State(unit, sampler);
|
||||
}
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -9,24 +9,22 @@
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params);
|
||||
void SamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint* param);
|
||||
void SamplerParameterIiv(GLuint sampler, GLenum pname, const GLint* param);
|
||||
void SamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param);
|
||||
void SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param);
|
||||
void SamplerParameteri(GLuint sampler, GLenum pname, GLint param);
|
||||
void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param);
|
||||
GLboolean IsSampler(GLuint sampler);
|
||||
void GetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint* params);
|
||||
void GetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint* params);
|
||||
void GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params);
|
||||
void GenSamplers(GLsizei count, GLuint* samplers);
|
||||
void DeleteSamplers(GLsizei count, const GLuint* samplers);
|
||||
void CreateSamplers(GLsizei n, GLuint* samplers);
|
||||
void BindSamplers(GLuint first, GLsizei count, const GLuint* samplers);
|
||||
void BindSampler(GLuint unit, GLuint sampler);
|
||||
} // namespace MG_Impl::GLImpl
|
||||
} // namespace MobileGL
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params);
|
||||
void SamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint* param);
|
||||
void SamplerParameterIiv(GLuint sampler, GLenum pname, const GLint* param);
|
||||
void SamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param);
|
||||
void SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param);
|
||||
void SamplerParameteri(GLuint sampler, GLenum pname, GLint param);
|
||||
void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param);
|
||||
GLboolean IsSampler(GLuint sampler);
|
||||
void GetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint* params);
|
||||
void GetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint* params);
|
||||
void GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params);
|
||||
void GenSamplers(GLsizei count, GLuint* samplers);
|
||||
void DeleteSamplers(GLsizei count, const GLuint* samplers);
|
||||
void CreateSamplers(GLsizei n, GLuint* samplers);
|
||||
void BindSamplers(GLuint first, GLsizei count, const GLuint* samplers);
|
||||
void BindSampler(GLuint unit, GLuint sampler);
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -11,126 +11,122 @@
|
||||
#include <MG_State/GLState/ErrorState/Error.h>
|
||||
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
namespace SamplerImpl {
|
||||
Bool ValidateSamplerName(GLuint sampler) {
|
||||
if (!MG_State::pGLContext->ValidateSamplerName(sampler)) {
|
||||
namespace MobileGL::MG_Impl::GLImpl::SamplerImpl {
|
||||
Bool ValidateSamplerName(GLuint sampler) {
|
||||
if (!MG_State::pGLContext->ValidateSamplerName(sampler)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerName",
|
||||
std::format("Invalid sampler name {}", sampler)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateSamplerObject(GLuint sampler) {
|
||||
if (!MG_State::pGLContext->ValidateSamplerObject(sampler)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerObject",
|
||||
std::format("Sampler object {} does not exist", sampler)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateSamplerParam(GLenum pname, GLenum param) {
|
||||
using namespace MG_Util;
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_WRAP_S:
|
||||
case GL_TEXTURE_WRAP_T:
|
||||
case GL_TEXTURE_WRAP_R:
|
||||
if (MG_Util::ConvertGLEnumToSamplerWrapMode(param) == SamplerWrapMode::Unknown) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||
"Invalid wrap mode parameter"));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_MIN_FILTER:
|
||||
if (MG_Util::ConvertGLEnumToSamplerFilterMode(param) == SamplerFilterMode::Unknown) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||
"Invalid min filter parameter"));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_MAG_FILTER:
|
||||
if (param != GL_NEAREST && param != GL_LINEAR) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||
"Invalid mag filter parameter"));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_COMPARE_MODE:
|
||||
if (param != GL_NONE && param != GL_COMPARE_REF_TO_TEXTURE) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||
"Invalid compare mode parameter"));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_COMPARE_FUNC:
|
||||
if (param < GL_LEQUAL || param > GL_ALWAYS) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||
"Invalid compare function parameter"));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||
"Invalid pname for sampler parameter"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateSamplerFloatParam(GLenum pname, GLfloat param) {
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_MIN_LOD:
|
||||
case GL_TEXTURE_MAX_LOD:
|
||||
case GL_TEXTURE_LOD_BIAS:
|
||||
return true;
|
||||
|
||||
case GL_TEXTURE_BORDER_COLOR:
|
||||
if (param < 0.0f || param > 1.0f) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerFloatParam",
|
||||
"Border color component out of [0,1] range"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
return ValidateSamplerParam(pname, static_cast<GLenum>(param));
|
||||
}
|
||||
}
|
||||
|
||||
Bool ValidateSamplerIntParam(GLenum pname, GLint param) {
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_BORDER_COLOR:
|
||||
if (param < 0 || param > 255) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerName",
|
||||
std::format("Invalid sampler name {}", sampler)));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerIntParam",
|
||||
"Border color component out of [0,255] range"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
return ValidateSamplerParam(pname, static_cast<GLenum>(param));
|
||||
}
|
||||
|
||||
Bool ValidateSamplerObject(GLuint sampler) {
|
||||
if (!MG_State::pGLContext->ValidateSamplerObject(sampler)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerObject",
|
||||
std::format("Sampler object {} does not exist", sampler)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateSamplerParam(GLenum pname, GLenum param) {
|
||||
using namespace MG_Util;
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_WRAP_S:
|
||||
case GL_TEXTURE_WRAP_T:
|
||||
case GL_TEXTURE_WRAP_R:
|
||||
if (MG_Util::ConvertGLEnumToSamplerWrapMode(param) == SamplerWrapMode::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||
"Invalid wrap mode parameter"));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_MIN_FILTER:
|
||||
if (MG_Util::ConvertGLEnumToSamplerFilterMode(param) == SamplerFilterMode::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||
"Invalid min filter parameter"));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_MAG_FILTER:
|
||||
if (param != GL_NEAREST && param != GL_LINEAR) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||
"Invalid mag filter parameter"));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_COMPARE_MODE:
|
||||
if (param != GL_NONE && param != GL_COMPARE_REF_TO_TEXTURE) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||
"Invalid compare mode parameter"));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_COMPARE_FUNC:
|
||||
if (param < GL_LEQUAL || param > GL_ALWAYS) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||
"Invalid compare function parameter"));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerParam",
|
||||
"Invalid pname for sampler parameter"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateSamplerFloatParam(GLenum pname, GLfloat param) {
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_MIN_LOD:
|
||||
case GL_TEXTURE_MAX_LOD:
|
||||
case GL_TEXTURE_LOD_BIAS:
|
||||
return true;
|
||||
|
||||
case GL_TEXTURE_BORDER_COLOR:
|
||||
if (param < 0.0f || param > 1.0f) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerFloatParam",
|
||||
"Border color component out of [0,1] range"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
return ValidateSamplerParam(pname, static_cast<GLenum>(param));
|
||||
}
|
||||
}
|
||||
|
||||
Bool ValidateSamplerIntParam(GLenum pname, GLint param) {
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_BORDER_COLOR:
|
||||
if (param < 0 || param > 255) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateSamplerIntParam",
|
||||
"Border color component out of [0,255] range"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
return ValidateSamplerParam(pname, static_cast<GLenum>(param));
|
||||
}
|
||||
}
|
||||
} // namespace SamplerImpl
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
}
|
||||
} // namespace MobileGL::MG_Impl::GLImpl::SamplerImpl
|
||||
|
||||
@@ -10,12 +10,10 @@
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/SamplerState/SamplerObject.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
namespace SamplerImpl {
|
||||
Bool ValidateSamplerName(GLuint sampler);
|
||||
Bool ValidateSamplerObject(GLuint sampler);
|
||||
Bool ValidateSamplerParam(GLenum pname, GLenum param);
|
||||
Bool ValidateSamplerFloatParam(GLenum pname, GLfloat param);
|
||||
Bool ValidateSamplerIntParam(GLenum pname, GLint param);
|
||||
} // namespace SamplerImpl
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
namespace MobileGL::MG_Impl::GLImpl::SamplerImpl {
|
||||
Bool ValidateSamplerName(GLuint sampler);
|
||||
Bool ValidateSamplerObject(GLuint sampler);
|
||||
Bool ValidateSamplerParam(GLenum pname, GLenum param);
|
||||
Bool ValidateSamplerFloatParam(GLenum pname, GLfloat param);
|
||||
Bool ValidateSamplerIntParam(GLenum pname, GLint param);
|
||||
} // namespace MobileGL::MG_Impl::GLImpl::SamplerImpl
|
||||
|
||||
@@ -10,36 +10,34 @@
|
||||
|
||||
#include "MG_State/GLState/Core.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Impl::GLImpl {
|
||||
GLsync FenceSync_Backend(GLenum condition, GLbitfield flags) {
|
||||
return 0;
|
||||
}
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
GLsync FenceSync_Backend(GLenum condition, GLbitfield flags) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLenum ClientWaitSync_Backend(GLsync sync, GLbitfield flags, GLuint64 timeout) {
|
||||
return 0;
|
||||
}
|
||||
GLenum ClientWaitSync_Backend(GLsync sync, GLbitfield flags, GLuint64 timeout) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DeleteSync_Backend(GLsync sync) {}
|
||||
void DeleteSync_Backend(GLsync sync) {}
|
||||
|
||||
GLsync FenceSync_State(GLenum condition, GLbitfield flags) {
|
||||
return 0;
|
||||
}
|
||||
GLsync FenceSync_State(GLenum condition, GLbitfield flags) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLenum ClientWaitSync_State(GLsync sync, GLbitfield flags, GLuint64 timeout) {
|
||||
return 0;
|
||||
}
|
||||
GLenum ClientWaitSync_State(GLsync sync, GLbitfield flags, GLuint64 timeout) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DeleteSync_State(GLsync sync) {}
|
||||
void DeleteSync_State(GLsync sync) {}
|
||||
|
||||
GLsync FenceSync(GLenum condition, GLbitfield flags) {
|
||||
return 0;
|
||||
}
|
||||
GLsync FenceSync(GLenum condition, GLbitfield flags) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
|
||||
return 0;
|
||||
}
|
||||
GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DeleteSync(GLsync sync) {}
|
||||
} // namespace MG_Impl::GLImpl
|
||||
} // namespace MobileGL
|
||||
void DeleteSync(GLsync sync) {}
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -9,10 +9,8 @@
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Impl::GLImpl {
|
||||
GLsync FenceSync(GLenum condition, GLbitfield flags);
|
||||
GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
|
||||
void DeleteSync(GLsync sync);
|
||||
} // namespace MG_Impl::GLImpl
|
||||
} // namespace MobileGL
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
GLsync FenceSync(GLenum condition, GLbitfield flags);
|
||||
GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
|
||||
void DeleteSync(GLsync sync);
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,48 +7,47 @@
|
||||
// End of Source File Header
|
||||
|
||||
#include "ProxyTexture.h"
|
||||
#include "MG_State/GLState/TextureState/TextureObject2D.h"
|
||||
#include "MG_Util/Types.h"
|
||||
#include <MG_State/GLState/TextureState/TextureObject2D.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
namespace TextureImpl {
|
||||
ProxyTextureManager* pProxyTextureManager;
|
||||
namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
|
||||
UniquePtr<ProxyTextureManager> pProxyTextureManager;
|
||||
|
||||
Bool IsProxyTextureTarget(TextureUploadTarget target) {
|
||||
switch (target) {
|
||||
case TextureUploadTarget::ProxyCubeMap:
|
||||
case TextureUploadTarget::ProxyTexture1DArray:
|
||||
case TextureUploadTarget::ProxyTexture2DArray:
|
||||
case TextureUploadTarget::ProxyTexture1D:
|
||||
case TextureUploadTarget::ProxyTexture2D:
|
||||
case TextureUploadTarget::ProxyTexture3D:
|
||||
case TextureUploadTarget::ProxyTexture2DMultisample:
|
||||
case TextureUploadTarget::ProxyTexture2DMultisampleArray:
|
||||
case TextureUploadTarget::ProxyTextureRectangle:
|
||||
case TextureUploadTarget::ProxyCubeMapArray:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
Bool IsProxyTextureTarget(TextureUploadTarget target) {
|
||||
switch (target) {
|
||||
case TextureUploadTarget::ProxyCubeMap:
|
||||
case TextureUploadTarget::ProxyTexture1DArray:
|
||||
case TextureUploadTarget::ProxyTexture2DArray:
|
||||
case TextureUploadTarget::ProxyTexture1D:
|
||||
case TextureUploadTarget::ProxyTexture2D:
|
||||
case TextureUploadTarget::ProxyTexture3D:
|
||||
case TextureUploadTarget::ProxyTexture2DMultisample:
|
||||
case TextureUploadTarget::ProxyTexture2DMultisampleArray:
|
||||
case TextureUploadTarget::ProxyTextureRectangle:
|
||||
case TextureUploadTarget::ProxyCubeMapArray:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SharedPtr<MG_State::GLState::ITextureObject> ProxyTextureManager::CreateOrReplaceProxyTextureObject(
|
||||
TextureUploadTarget target) {
|
||||
auto it = m_proxyTexturesMap.find(target);
|
||||
if (it != m_proxyTexturesMap.end()) {
|
||||
m_proxyTexturesMap.erase(it);
|
||||
}
|
||||
m_proxyTexturesMap[target] = MakeShared<MG_State::GLState::TextureObject2D>(0);
|
||||
return m_proxyTexturesMap[target];
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& ProxyTextureManager::CreateOrReplaceProxyTextureObject(
|
||||
TextureUploadTarget target) {
|
||||
auto it = m_proxyTexturesMap.find(target);
|
||||
if (it != m_proxyTexturesMap.end()) {
|
||||
m_proxyTexturesMap.erase(it);
|
||||
}
|
||||
auto& obj = m_proxyTexturesMap[target];
|
||||
obj = MakeShared<MG_State::GLState::TextureObject2D>(0);
|
||||
return obj;
|
||||
}
|
||||
|
||||
SharedPtr<MG_State::GLState::ITextureObject> ProxyTextureManager::GetProxyTextureObject(
|
||||
TextureUploadTarget target) {
|
||||
auto it = m_proxyTexturesMap.find(target);
|
||||
if (it != m_proxyTexturesMap.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& ProxyTextureManager::GetProxyTextureObject(
|
||||
TextureUploadTarget target) {
|
||||
auto it = m_proxyTexturesMap.find(target);
|
||||
if (it != m_proxyTexturesMap.end()) {
|
||||
return it->second;
|
||||
}
|
||||
} // namespace TextureImpl
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
static SharedPtr<MG_State::GLState::ITextureObject> nullTextureObject = nullptr;
|
||||
return nullTextureObject;
|
||||
}
|
||||
} // namespace MobileGL::MG_Impl::GLImpl::TextureImpl
|
||||
|
||||
@@ -10,19 +10,18 @@
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/Core.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
namespace TextureImpl {
|
||||
Bool IsProxyTextureTarget(TextureUploadTarget target);
|
||||
namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
|
||||
Bool IsProxyTextureTarget(TextureUploadTarget target);
|
||||
|
||||
class ProxyTextureManager {
|
||||
public:
|
||||
SharedPtr<MG_State::GLState::ITextureObject> CreateOrReplaceProxyTextureObject(TextureUploadTarget target);
|
||||
SharedPtr<MG_State::GLState::ITextureObject> GetProxyTextureObject(TextureUploadTarget target);
|
||||
class ProxyTextureManager {
|
||||
public:
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& CreateOrReplaceProxyTextureObject(
|
||||
TextureUploadTarget target);
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& GetProxyTextureObject(TextureUploadTarget target);
|
||||
|
||||
private:
|
||||
UnorderedMap<TextureUploadTarget, SharedPtr<MG_State::GLState::ITextureObject>> m_proxyTexturesMap;
|
||||
};
|
||||
private:
|
||||
UnorderedMap<TextureUploadTarget, SharedPtr<MG_State::GLState::ITextureObject>> m_proxyTexturesMap;
|
||||
};
|
||||
|
||||
extern ProxyTextureManager* pProxyTextureManager;
|
||||
} // namespace TextureImpl
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
extern UniquePtr<ProxyTextureManager> pProxyTextureManager;
|
||||
} // namespace MobileGL::MG_Impl::GLImpl::TextureImpl
|
||||
|
||||
@@ -15,309 +15,295 @@
|
||||
#include <MG_Util/Converters/MGToMG/TextureEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
namespace TextureImpl {
|
||||
Bool ValidateTextureTarget(TextureTarget target) {
|
||||
if (target == TextureTarget::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureTarget", "Invalid texture target"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
|
||||
Bool ValidateTextureTarget(TextureTarget target) {
|
||||
if (target == TextureTarget::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureTarget", "Invalid texture target"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureUploadTarget(TextureUploadTarget textureUploadTarget) {
|
||||
if (textureUploadTarget == TextureUploadTarget::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureUploadTarget",
|
||||
"Invalid texture upload target"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureName(Uint texture, Bool allowZero) {
|
||||
if (texture == 0) {
|
||||
if (allowZero) return true;
|
||||
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureName", "Texture name cannot be zero"));
|
||||
return false;
|
||||
}
|
||||
|
||||
Bool ValidateTextureUploadTarget(TextureUploadTarget textureUploadTarget) {
|
||||
if (textureUploadTarget == TextureUploadTarget::Unknown) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||
"ValidateTextureUploadTarget",
|
||||
"Invalid texture upload target"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
if (!MG_State::pGLContext->ValidateTextureName(texture)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureName", "Invalid texture name"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureInputFormat(TextureInputFormat format) {
|
||||
if (format == TextureInputFormat::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInputFormat",
|
||||
"Invalid texture input format"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTexturePixelDataType(TexturePixelDataType texturePixelDataType) {
|
||||
if (texturePixelDataType == TexturePixelDataType::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTexturePixelDataType",
|
||||
"Invalid texture pixel data type"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureLevelNumber(GLint level) {
|
||||
if (level < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureLevelNumber",
|
||||
"Texture level must be non-negative"));
|
||||
return false;
|
||||
}
|
||||
|
||||
Bool ValidateTextureName(Uint texture, Bool allowZero) {
|
||||
if (texture == 0) {
|
||||
if (allowZero) return true;
|
||||
// TODO: GL_INVALID_VALUE may be generated if level is greater than log2(max), where max is the returned
|
||||
// value of GL_MAX_TEXTURE_SIZE.
|
||||
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureName",
|
||||
"Texture name cannot be zero"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!MG_State::pGLContext->ValidateTextureName(texture)) {
|
||||
Bool ValidateTextureSizeWithTextureUploadTarget(TextureUploadTarget target, GLsizei width, GLsizei height) {
|
||||
if (target == TextureUploadTarget::CubeMapPositiveX || target == TextureUploadTarget::CubeMapNegativeX ||
|
||||
target == TextureUploadTarget::CubeMapPositiveY || target == TextureUploadTarget::CubeMapNegativeY ||
|
||||
target == TextureUploadTarget::CubeMapPositiveZ || target == TextureUploadTarget::CubeMapNegativeZ) {
|
||||
if (width != height) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureName", "Invalid texture name"));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget",
|
||||
"Width and height must be equal for cube map textures"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureInputFormat(TextureInputFormat format) {
|
||||
if (format == TextureInputFormat::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInputFormat",
|
||||
"Invalid texture input format"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTexturePixelDataType(TexturePixelDataType texturePixelDataType) {
|
||||
if (texturePixelDataType == TexturePixelDataType::Unknown) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||
"ValidateTexturePixelDataType",
|
||||
"Invalid texture pixel data type"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureLevelNumber(GLint level) {
|
||||
if (level < 0) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||
"ValidateTextureLevelNumber",
|
||||
"Texture level must be non-negative"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: GL_INVALID_VALUE may be generated if level is greater than log2(max), where max is the returned
|
||||
// value of GL_MAX_TEXTURE_SIZE.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureSizeWithTextureUploadTarget(TextureUploadTarget target, GLsizei width, GLsizei height) {
|
||||
if (target == TextureUploadTarget::CubeMapPositiveX || target == TextureUploadTarget::CubeMapNegativeX ||
|
||||
target == TextureUploadTarget::CubeMapPositiveY || target == TextureUploadTarget::CubeMapNegativeY ||
|
||||
target == TextureUploadTarget::CubeMapPositiveZ || target == TextureUploadTarget::CubeMapNegativeZ) {
|
||||
if (width != height) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget",
|
||||
"Width and height must be equal for cube map textures"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(target == TextureUploadTarget::Texture1DArray ||
|
||||
target == TextureUploadTarget::ProxyTexture1DArray)) {
|
||||
if (height < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget",
|
||||
"Height must be greater than or equal to zero"));
|
||||
return false;
|
||||
}
|
||||
// TODO: GL_INVALID_VALUE is generated if target is not GL_TEXTURE_1D_ARRAY or GL_PROXY_TEXTURE_1D_ARRAY
|
||||
// and height is greater than GL_MAX_TEXTURE_SIZE.
|
||||
}
|
||||
|
||||
if (target == TextureUploadTarget::Texture1DArray || target == TextureUploadTarget::ProxyTexture1DArray) {
|
||||
if (height < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget",
|
||||
"Height must be greater than or equal to zero"));
|
||||
return false;
|
||||
}
|
||||
// TODO: GL_INVALID_VALUE is generated if target is GL_TEXTURE_1D_ARRAY or GL_PROXY_TEXTURE_1D_ARRAY and
|
||||
// height is greater than GL_MAX_ARRAY_TEXTURE_LAYERS.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureSizeRange(SizeT width, SizeT height, SizeT depth) {
|
||||
if (width < 0 || height < 0 || depth < 0) {
|
||||
if (!(target == TextureUploadTarget::Texture1DArray || target == TextureUploadTarget::ProxyTexture1DArray)) {
|
||||
if (height < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeRange",
|
||||
"Width and height must be greater than zero"));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget",
|
||||
"Height must be greater than or equal to zero"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: GL_INVALID_VALUE is generated if width is greater than GL_MAX_TEXTURE_SIZE.
|
||||
|
||||
return true;
|
||||
// TODO: GL_INVALID_VALUE is generated if target is not GL_TEXTURE_1D_ARRAY or GL_PROXY_TEXTURE_1D_ARRAY
|
||||
// and height is greater than GL_MAX_TEXTURE_SIZE.
|
||||
}
|
||||
|
||||
Bool ValidateTextureInternalFormat(TextureInternalFormat format) {
|
||||
if (format == TextureInternalFormat::Unknown) {
|
||||
if (target == TextureUploadTarget::Texture1DArray || target == TextureUploadTarget::ProxyTexture1DArray) {
|
||||
if (height < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormat",
|
||||
"Invalid texture sized internal format"));
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeWithTarget",
|
||||
"Height must be greater than or equal to zero"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
// TODO: GL_INVALID_VALUE is generated if target is GL_TEXTURE_1D_ARRAY or GL_PROXY_TEXTURE_1D_ARRAY and
|
||||
// height is greater than GL_MAX_ARRAY_TEXTURE_LAYERS.
|
||||
}
|
||||
|
||||
Bool ValidateTextureBorderNumber(Int border) {
|
||||
if (border != 0) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||
"ValidateTextureBorderNumber",
|
||||
"Border must be zero"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureSizeRange(SizeT width, SizeT height, SizeT depth) {
|
||||
if (width < 0 || height < 0 || depth < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSizeRange",
|
||||
"Width and height must be greater than zero"));
|
||||
return false;
|
||||
}
|
||||
|
||||
Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format,
|
||||
TextureInternalFormat internalFormat,
|
||||
TexturePixelDataType type) {
|
||||
if (type == TexturePixelDataType::UnsignedByte332 || type == TexturePixelDataType::UnsignedByte233Rev ||
|
||||
type == TexturePixelDataType::UnsignedShort565 || type == TexturePixelDataType::UnsignedShort565Rev ||
|
||||
type == TexturePixelDataType::UnsignedInt101111Rev) {
|
||||
if (format != TextureInputFormat::RGB) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||
"ValidateTextureInternalFormatCompatibleWithInput",
|
||||
"Invalid format for the given type"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// TODO: GL_INVALID_VALUE is generated if width is greater than GL_MAX_TEXTURE_SIZE.
|
||||
|
||||
if (type == TexturePixelDataType::UnsignedShort4444 || type == TexturePixelDataType::UnsignedShort4444Rev ||
|
||||
type == TexturePixelDataType::UnsignedShort5551 || type == TexturePixelDataType::UnsignedShort1555Rev ||
|
||||
type == TexturePixelDataType::UnsignedInt8888 || type == TexturePixelDataType::UnsignedInt8888Rev ||
|
||||
type == TexturePixelDataType::UnsignedInt1010102 ||
|
||||
type == TexturePixelDataType::UnsignedInt2101010Rev ||
|
||||
type == TexturePixelDataType::UnsignedInt5999Rev) {
|
||||
if (format != TextureInputFormat::RGBA && format != TextureInputFormat::BGRA) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||
"ValidateTextureInternalFormatCompatibleWithInput",
|
||||
"Invalid format for the given type"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (internalFormat == TextureInternalFormat::DepthComponent ||
|
||||
internalFormat == TextureInternalFormat::DepthComponent16 ||
|
||||
internalFormat == TextureInternalFormat::DepthComponent24 ||
|
||||
internalFormat == TextureInternalFormat::DepthComponent32F) {
|
||||
if (format != TextureInputFormat::DepthComponent) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||
"ValidateTextureInternalFormatCompatibleWithInput",
|
||||
"Invalid format for depth component internal format"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Bool ValidateTextureInternalFormat(TextureInternalFormat format) {
|
||||
if (format == TextureInternalFormat::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormat",
|
||||
"Invalid texture sized internal format"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (format == TextureInputFormat::DepthComponent &&
|
||||
(internalFormat != TextureInternalFormat::DepthComponent &&
|
||||
internalFormat != TextureInternalFormat::DepthComponent16 &&
|
||||
internalFormat != TextureInternalFormat::DepthComponent24 &&
|
||||
internalFormat != TextureInternalFormat::DepthComponent32F &&
|
||||
internalFormat != TextureInternalFormat::DepthComponent32 // workaround for Minecraft 1.21.5+
|
||||
)) {
|
||||
Bool ValidateTextureBorderNumber(Int border) {
|
||||
if (border != 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureBorderNumber", "Border must be zero"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format,
|
||||
TextureInternalFormat internalFormat,
|
||||
TexturePixelDataType type) {
|
||||
if (type == TexturePixelDataType::UnsignedByte332 || type == TexturePixelDataType::UnsignedByte233Rev ||
|
||||
type == TexturePixelDataType::UnsignedShort565 || type == TexturePixelDataType::UnsignedShort565Rev ||
|
||||
type == TexturePixelDataType::UnsignedInt101111Rev) {
|
||||
if (format != TextureInputFormat::RGB) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
|
||||
"Invalid internal format for depth component format"));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
|
||||
"Invalid format for the given type"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureLevelWithUploadTarget(TextureUploadTarget target, Int level) {
|
||||
if (target == TextureUploadTarget::TextureRectangle ||
|
||||
target == TextureUploadTarget::ProxyTextureRectangle) {
|
||||
if (level != 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureLevelWithUploadTarget",
|
||||
"Level must be zero for rectangle textures"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureObject(SharedPtr<MG_State::GLState::ITextureObject> textureObject) {
|
||||
if (!textureObject) {
|
||||
if (type == TexturePixelDataType::UnsignedShort4444 || type == TexturePixelDataType::UnsignedShort4444Rev ||
|
||||
type == TexturePixelDataType::UnsignedShort5551 || type == TexturePixelDataType::UnsignedShort1555Rev ||
|
||||
type == TexturePixelDataType::UnsignedInt8888 || type == TexturePixelDataType::UnsignedInt8888Rev ||
|
||||
type == TexturePixelDataType::UnsignedInt1010102 || type == TexturePixelDataType::UnsignedInt2101010Rev ||
|
||||
type == TexturePixelDataType::UnsignedInt5999Rev) {
|
||||
if (format != TextureInputFormat::RGBA && format != TextureInputFormat::BGRA) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureObject", "Texture object is null"));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
|
||||
"Invalid format for the given type"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureTargetUniformity(SharedPtr<MG_State::GLState::ITextureObject> textureObject,
|
||||
TextureTarget target) {
|
||||
if (!textureObject) return true; // should be created later
|
||||
TextureTarget prevTarget = textureObject->GetTarget();
|
||||
if (prevTarget != target) {
|
||||
if (internalFormat == TextureInternalFormat::DepthComponent ||
|
||||
internalFormat == TextureInternalFormat::DepthComponent16 ||
|
||||
internalFormat == TextureInternalFormat::DepthComponent24 ||
|
||||
internalFormat == TextureInternalFormat::DepthComponent32F) {
|
||||
if (format != TextureInputFormat::DepthComponent) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureTargetUniformity",
|
||||
"Texture target does not match the previously created texture"));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
|
||||
"Invalid format for depth component internal format"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureSubImageOffsets(SharedPtr<MG_State::GLState::ITextureObject> textureObject, Int xoffset,
|
||||
Int width, Int yoffset, Int height, Int zoffset, Int depth) {
|
||||
auto baseSize = textureObject->GetBaseSize();
|
||||
if (xoffset < 0 || (xoffset + width) > baseSize.x()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
|
||||
"xoffset must be non-negative and (xoffset + width) must not exceed "
|
||||
"the texture width."));
|
||||
return false;
|
||||
}
|
||||
if (baseSize.y() == 0) return true;
|
||||
|
||||
if (yoffset < 0 || (yoffset + height) > baseSize.y()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
|
||||
"yoffset must be non-negative and (yoffset + height) must not exceed "
|
||||
"the texture height."));
|
||||
return false;
|
||||
}
|
||||
if (baseSize.z() == 0) return true;
|
||||
|
||||
if (zoffset < 0 || (zoffset + depth) > baseSize.z()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
|
||||
"zoffset must be non-negative and (zoffset + depth) must not exceed "
|
||||
"the texture depth."));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
if (format == TextureInputFormat::DepthComponent &&
|
||||
(internalFormat != TextureInternalFormat::DepthComponent &&
|
||||
internalFormat != TextureInternalFormat::DepthComponent16 &&
|
||||
internalFormat != TextureInternalFormat::DepthComponent24 &&
|
||||
internalFormat != TextureInternalFormat::DepthComponent32F &&
|
||||
internalFormat != TextureInternalFormat::DepthComponent32 // workaround for Minecraft 1.21.5+
|
||||
)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureInternalFormatCompatibleWithInput",
|
||||
"Invalid internal format for depth component format"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateBaseInternalFormatMatch(TextureInternalFormat format1, TextureInternalFormat format2) {
|
||||
auto unsizedFormat1 = MG_Util::ConvertInternalFormatToUnsized(format1);
|
||||
auto unsizedFormat2 = MG_Util::ConvertInternalFormatToUnsized(format2);
|
||||
if (unsizedFormat1 != unsizedFormat2) {
|
||||
Bool ValidateTextureLevelWithUploadTarget(TextureUploadTarget target, Int level) {
|
||||
if (target == TextureUploadTarget::TextureRectangle || target == TextureUploadTarget::ProxyTextureRectangle) {
|
||||
if (level != 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>(
|
||||
std::format("MG_Impl/GLImpl", "ValidateBaseInternalFormatMatch",
|
||||
"The base internal format of the two formats do not match ({} vs. {})",
|
||||
MG_Util::ConvertTextureInternalFormatToString(unsizedFormat1).c_str(),
|
||||
MG_Util::ConvertTextureInternalFormatToString(unsizedFormat2).c_str())));
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureLevelWithUploadTarget",
|
||||
"Level must be zero for rectangle textures"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} // namespace TextureImpl
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureObject(SharedPtr<MG_State::GLState::ITextureObject> textureObject) {
|
||||
if (!textureObject) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureObject", "Texture object is null"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureTargetUniformity(SharedPtr<MG_State::GLState::ITextureObject> textureObject,
|
||||
TextureTarget target) {
|
||||
if (!textureObject) return true; // should be created later
|
||||
TextureTarget prevTarget = textureObject->GetTarget();
|
||||
if (prevTarget != target) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureTargetUniformity",
|
||||
"Texture target does not match the previously created texture"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateTextureSubImageOffsets(SharedPtr<MG_State::GLState::ITextureObject> textureObject, Int xoffset,
|
||||
Int width, Int yoffset, Int height, Int zoffset, Int depth) {
|
||||
auto baseSize = textureObject->GetBaseSize();
|
||||
if (xoffset < 0 || (xoffset + width) > baseSize.x()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
|
||||
"xoffset must be non-negative and (xoffset + width) must not exceed "
|
||||
"the texture width."));
|
||||
return false;
|
||||
}
|
||||
if (baseSize.y() == 0) return true;
|
||||
|
||||
if (yoffset < 0 || (yoffset + height) > baseSize.y()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
|
||||
"yoffset must be non-negative and (yoffset + height) must not exceed "
|
||||
"the texture height."));
|
||||
return false;
|
||||
}
|
||||
if (baseSize.z() == 0) return true;
|
||||
|
||||
if (zoffset < 0 || (zoffset + depth) > baseSize.z()) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateTextureSubImageOffsets",
|
||||
"zoffset must be non-negative and (zoffset + depth) must not exceed "
|
||||
"the texture depth."));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateBaseInternalFormatMatch(TextureInternalFormat format1, TextureInternalFormat format2) {
|
||||
auto unsizedFormat1 = MG_Util::ConvertInternalFormatToUnsized(format1);
|
||||
auto unsizedFormat2 = MG_Util::ConvertInternalFormatToUnsized(format2);
|
||||
if (unsizedFormat1 != unsizedFormat2) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
std::format("MG_Impl/GLImpl", "ValidateBaseInternalFormatMatch",
|
||||
"The base internal format of the two formats do not match ({} vs. {})",
|
||||
MG_Util::ConvertTextureInternalFormatToString(unsizedFormat1).c_str(),
|
||||
MG_Util::ConvertTextureInternalFormatToString(unsizedFormat2).c_str())));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} // namespace TextureImpl
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
} // namespace MobileGL::MG_Impl::GLImpl::TextureImpl
|
||||
|
||||
@@ -12,27 +12,25 @@
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/TextureState/TextureObject.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
namespace TextureImpl {
|
||||
Bool ValidateTextureTarget(TextureTarget target);
|
||||
Bool ValidateTextureUploadTarget(TextureUploadTarget textureUploadTarget);
|
||||
Bool ValidateTextureName(Uint texture, Bool allowZero = false);
|
||||
Bool ValidateTextureInputFormat(TextureInputFormat format);
|
||||
Bool ValidateTexturePixelDataType(TexturePixelDataType texturePixelDataType);
|
||||
Bool ValidateTextureLevelNumber(Int level);
|
||||
Bool ValidateTextureSizeWithTextureUploadTarget(TextureUploadTarget target, GLsizei width, GLsizei height);
|
||||
Bool ValidateTextureSizeRange(SizeT width, SizeT height, SizeT depth);
|
||||
Bool ValidateTextureInternalFormat(TextureInternalFormat format);
|
||||
Bool ValidateTextureBorderNumber(Int border);
|
||||
Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format,
|
||||
TextureInternalFormat internalFormat,
|
||||
TexturePixelDataType type);
|
||||
Bool ValidateTextureLevelWithUploadTarget(TextureUploadTarget target, Int level);
|
||||
Bool ValidateTextureObject(SharedPtr<MG_State::GLState::ITextureObject> textureObject);
|
||||
Bool ValidateTextureTargetUniformity(SharedPtr<MG_State::GLState::ITextureObject> textureObject,
|
||||
TextureTarget target);
|
||||
Bool ValidateTextureSubImageOffsets(SharedPtr<MG_State::GLState::ITextureObject> textureObject, Int xoffset,
|
||||
Int width, Int yoffset = 0, Int height = 0, Int zoffset = 0, Int depth = 0);
|
||||
Bool ValidateBaseInternalFormatMatch(TextureInternalFormat format1, TextureInternalFormat format2);
|
||||
} // namespace TextureImpl
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
|
||||
Bool ValidateTextureTarget(TextureTarget target);
|
||||
Bool ValidateTextureUploadTarget(TextureUploadTarget textureUploadTarget);
|
||||
Bool ValidateTextureName(Uint texture, Bool allowZero = false);
|
||||
Bool ValidateTextureInputFormat(TextureInputFormat format);
|
||||
Bool ValidateTexturePixelDataType(TexturePixelDataType texturePixelDataType);
|
||||
Bool ValidateTextureLevelNumber(Int level);
|
||||
Bool ValidateTextureSizeWithTextureUploadTarget(TextureUploadTarget target, GLsizei width, GLsizei height);
|
||||
Bool ValidateTextureSizeRange(SizeT width, SizeT height, SizeT depth);
|
||||
Bool ValidateTextureInternalFormat(TextureInternalFormat format);
|
||||
Bool ValidateTextureBorderNumber(Int border);
|
||||
Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format,
|
||||
TextureInternalFormat internalFormat,
|
||||
TexturePixelDataType type);
|
||||
Bool ValidateTextureLevelWithUploadTarget(TextureUploadTarget target, Int level);
|
||||
Bool ValidateTextureObject(SharedPtr<MG_State::GLState::ITextureObject> textureObject);
|
||||
Bool ValidateTextureTargetUniformity(SharedPtr<MG_State::GLState::ITextureObject> textureObject,
|
||||
TextureTarget target);
|
||||
Bool ValidateTextureSubImageOffsets(SharedPtr<MG_State::GLState::ITextureObject> textureObject, Int xoffset,
|
||||
Int width, Int yoffset = 0, Int height = 0, Int zoffset = 0, Int depth = 0);
|
||||
Bool ValidateBaseInternalFormatMatch(TextureInternalFormat format1, TextureInternalFormat format2);
|
||||
} // namespace MobileGL::MG_Impl::GLImpl::TextureImpl
|
||||
|
||||
@@ -12,222 +12,216 @@
|
||||
#include <MG_State/GLState/ErrorState/Error.h>
|
||||
#include <MG_Util/Converters/GLToMG/DataTypeConverter.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Impl::GLImpl {
|
||||
void DisableVertexAttribArray_State(GLuint index) {
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
void DisableVertexAttribArray_State(GLuint index) {
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
|
||||
|
||||
auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!vao) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||
"EnableVertexAttribArray_State",
|
||||
"No vertex array object is bound."));
|
||||
return;
|
||||
}
|
||||
|
||||
vao->DisableAttribute(index);
|
||||
auto& vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!vao) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||
"EnableVertexAttribArray_State",
|
||||
"No vertex array object is bound."));
|
||||
return;
|
||||
}
|
||||
|
||||
void EnableVertexAttribArray_State(GLuint index) {
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
|
||||
vao->DisableAttribute(index);
|
||||
}
|
||||
|
||||
auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!vao) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||
"EnableVertexAttribArray_State",
|
||||
"No vertex array object is bound."));
|
||||
return;
|
||||
}
|
||||
void EnableVertexAttribArray_State(GLuint index) {
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
|
||||
|
||||
vao->EnableAttribute(index);
|
||||
auto& vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!vao) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||
"EnableVertexAttribArray_State",
|
||||
"No vertex array object is bound."));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: implement GL_BGRA support
|
||||
void VertexAttribIPointer_State(GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer) {
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
|
||||
vao->EnableAttribute(index);
|
||||
}
|
||||
|
||||
DataType dataType = MG_Util::ConvertGLEnumToDataType(type);
|
||||
if (!VertexArrayImpl::ValidateVertexAttribPointerParams(index, size, dataType, stride)) return;
|
||||
// TODO: implement GL_BGRA support
|
||||
void VertexAttribIPointer_State(GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer) {
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
|
||||
|
||||
auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!vao) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||
"VertexAttribPointer_State",
|
||||
"No vertex array object is bound."));
|
||||
return;
|
||||
}
|
||||
DataType dataType = MG_Util::ConvertGLEnumToDataType(type);
|
||||
if (!VertexArrayImpl::ValidateVertexAttribPointerParams(index, size, dataType, stride)) return;
|
||||
|
||||
auto& vboSlot = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex);
|
||||
auto vbo = vboSlot.GetBoundObject();
|
||||
if (!vbo) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "VertexAttribPointer_State",
|
||||
"No buffer is bound to GL_ARRAY_BUFFER."));
|
||||
return;
|
||||
}
|
||||
|
||||
SizeT offset = reinterpret_cast<SizeT>(pointer);
|
||||
|
||||
vao->SetAttributeFormat(index, size, dataType, false, stride, offset, true);
|
||||
vao->BindAttributeBuffer(index, vbo);
|
||||
auto& vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!vao) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "VertexAttribPointer_State",
|
||||
"No vertex array object is bound."));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: implement GL_BGRA support
|
||||
void VertexAttribPointer_State(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
|
||||
const void* pointer) {
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
|
||||
|
||||
DataType dataType = MG_Util::ConvertGLEnumToDataType(type);
|
||||
if (!VertexArrayImpl::ValidateVertexAttribPointerParams(index, size, dataType, stride)) return;
|
||||
|
||||
auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!vao) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||
"VertexAttribPointer_State",
|
||||
"No vertex array object is bound."));
|
||||
return;
|
||||
}
|
||||
|
||||
auto& vboSlot = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Vertex);
|
||||
auto vbo = vboSlot.GetBoundObject();
|
||||
if (!vbo) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "VertexAttribPointer_State",
|
||||
"No buffer is bound to GL_ARRAY_BUFFER."));
|
||||
return;
|
||||
}
|
||||
|
||||
SizeT offset = reinterpret_cast<SizeT>(pointer);
|
||||
|
||||
vao->SetAttributeFormat(index, size, dataType, normalized, stride, offset, false);
|
||||
vao->BindAttributeBuffer(index, vbo);
|
||||
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;
|
||||
}
|
||||
|
||||
void BindVertexArray_State(GLuint array) {
|
||||
if (array == 0) {
|
||||
auto offset = reinterpret_cast<SizeT>(pointer);
|
||||
|
||||
vao->SetAttributeFormat(index, size, dataType, false, stride, offset, true);
|
||||
vao->BindAttributeBuffer(index, vbo);
|
||||
}
|
||||
|
||||
// TODO: implement GL_BGRA support
|
||||
void VertexAttribPointer_State(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
|
||||
const void* pointer) {
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
|
||||
|
||||
DataType dataType = MG_Util::ConvertGLEnumToDataType(type);
|
||||
if (!VertexArrayImpl::ValidateVertexAttribPointerParams(index, size, dataType, stride)) return;
|
||||
|
||||
auto& vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!vao) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "VertexAttribPointer_State",
|
||||
"No vertex array object is bound."));
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
vao->SetAttributeFormat(index, size, dataType, normalized, stride, offset, false);
|
||||
vao->BindAttributeBuffer(index, vbo);
|
||||
}
|
||||
|
||||
void BindVertexArray_State(GLuint array) {
|
||||
if (array == 0) {
|
||||
MG_State::pGLContext->BindVertexArray(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!VertexArrayImpl::ValidateVertexArrayName(array)) return;
|
||||
|
||||
if (!MG_State::pGLContext->ValidateVertexArrayObject(array)) {
|
||||
MG_State::pGLContext->CreateVertexArrayObject(array);
|
||||
}
|
||||
|
||||
MG_State::pGLContext->BindVertexArray(array);
|
||||
}
|
||||
|
||||
void DeleteVertexArrays_State(GLsizei n, const GLuint* arrays) {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteVertexArrays_State", "n must be non-negative."));
|
||||
return;
|
||||
}
|
||||
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
GLuint vao = arrays[i];
|
||||
if (vao == 0) continue;
|
||||
|
||||
if (!VertexArrayImpl::ValidateVertexArrayName(vao)) continue;
|
||||
|
||||
if (MG_State::pGLContext->GetBoundVertexArray() &&
|
||||
MG_State::pGLContext->GetBoundVertexArray() == MG_State::pGLContext->GetVertexArrayObject(vao)) {
|
||||
MG_State::pGLContext->BindVertexArray(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!VertexArrayImpl::ValidateVertexArrayName(array)) return;
|
||||
MG_State::pGLContext->MarkVertexArrayForDeletion(vao);
|
||||
}
|
||||
}
|
||||
|
||||
if (!MG_State::pGLContext->ValidateVertexArrayObject(array)) {
|
||||
MG_State::pGLContext->CreateVertexArrayObject(array);
|
||||
}
|
||||
|
||||
MG_State::pGLContext->BindVertexArray(array);
|
||||
void GenVertexArrays_State(GLsizei n, GLuint* arrays) {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenVertexArrays_State", "n must be non-negative."));
|
||||
return;
|
||||
}
|
||||
|
||||
void DeleteVertexArrays_State(GLsizei n, const GLuint* arrays) {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "DeleteVertexArrays_State",
|
||||
"n must be non-negative."));
|
||||
return;
|
||||
}
|
||||
static thread_local Vector<Uint> vaos;
|
||||
MG_State::pGLContext->GenVertexArrayNames(n, vaos);
|
||||
Memcpy(arrays, vaos.data(), n * sizeof(GLuint));
|
||||
}
|
||||
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
GLuint vao = arrays[i];
|
||||
if (vao == 0) continue;
|
||||
GLboolean IsVertexArray_State(GLuint array) {
|
||||
if (array == 0) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "IsVertexArray_State",
|
||||
"Vertex array name 0 is not supported."));
|
||||
return GL_FALSE;
|
||||
}
|
||||
if (!VertexArrayImpl::ValidateVertexArrayName(array)) return GL_FALSE;
|
||||
if (!MG_State::pGLContext->ValidateVertexArrayObject(array)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "IsVertexArray_State",
|
||||
std::format("Vertex array object {} does not exist.", array)));
|
||||
return GL_FALSE;
|
||||
}
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
if (!VertexArrayImpl::ValidateVertexArrayName(vao)) continue;
|
||||
void VertexAttribDivisor_State(GLuint index, GLuint divisor) {
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
|
||||
|
||||
if (MG_State::pGLContext->GetBoundVertexArray() &&
|
||||
MG_State::pGLContext->GetBoundVertexArray() == MG_State::pGLContext->GetVertexArrayObject(vao)) {
|
||||
MG_State::pGLContext->BindVertexArray(0);
|
||||
}
|
||||
|
||||
MG_State::pGLContext->MarkVertexArrayForDeletion(vao);
|
||||
}
|
||||
auto& vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!vao) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "VertexAttribDivisor_State",
|
||||
"No vertex array object is bound."));
|
||||
return;
|
||||
}
|
||||
|
||||
void GenVertexArrays_State(GLsizei n, GLuint* arrays) {
|
||||
if (n < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "GenVertexArrays_State", "n must be non-negative."));
|
||||
return;
|
||||
}
|
||||
vao->SetAttributeDivisor(index, divisor);
|
||||
}
|
||||
|
||||
auto vaoNames = MG_State::pGLContext->GenVertexArrayNames(n);
|
||||
Copy(vaoNames.data(), arrays, vaoNames.size());
|
||||
}
|
||||
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
||||
void VertexAttribDivisor(GLuint index, GLuint divisor) {
|
||||
VertexAttribDivisor_State(index, divisor);
|
||||
}
|
||||
|
||||
GLboolean IsVertexArray_State(GLuint array) {
|
||||
if (array == 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue, MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "IsVertexArray_State",
|
||||
"Vertex array name 0 is not supported."));
|
||||
return GL_FALSE;
|
||||
}
|
||||
if (!VertexArrayImpl::ValidateVertexArrayName(array)) return GL_FALSE;
|
||||
if (!MG_State::pGLContext->ValidateVertexArrayObject(array)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "IsVertexArray_State",
|
||||
std::format("Vertex array object {} does not exist.", array)));
|
||||
return GL_FALSE;
|
||||
}
|
||||
return GL_TRUE;
|
||||
}
|
||||
GLboolean IsVertexArray(GLuint array) {
|
||||
return IsVertexArray_State(array);
|
||||
}
|
||||
|
||||
void VertexAttribDivisor_State(GLuint index, GLuint divisor) {
|
||||
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
|
||||
void DisableVertexAttribArray(GLuint index) {
|
||||
DisableVertexAttribArray_State(index);
|
||||
}
|
||||
|
||||
auto vao = MG_State::pGLContext->GetBoundVertexArray();
|
||||
if (!vao) {
|
||||
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl",
|
||||
"VertexAttribDivisor_State",
|
||||
"No vertex array object is bound."));
|
||||
return;
|
||||
}
|
||||
void EnableVertexAttribArray(GLuint index) {
|
||||
EnableVertexAttribArray_State(index);
|
||||
}
|
||||
|
||||
vao->SetAttributeDivisor(index, divisor);
|
||||
}
|
||||
void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer) {
|
||||
VertexAttribIPointer_State(index, size, type, stride, pointer);
|
||||
}
|
||||
|
||||
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
||||
void VertexAttribDivisor(GLuint index, GLuint divisor) {
|
||||
VertexAttribDivisor_State(index, divisor);
|
||||
}
|
||||
void VertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
|
||||
const void* pointer) {
|
||||
VertexAttribPointer_State(index, size, type, normalized, stride, pointer);
|
||||
}
|
||||
|
||||
GLboolean IsVertexArray(GLuint array) {
|
||||
return IsVertexArray_State(array);
|
||||
}
|
||||
void BindVertexArray(GLuint array) {
|
||||
BindVertexArray_State(array);
|
||||
}
|
||||
|
||||
void DisableVertexAttribArray(GLuint index) {
|
||||
DisableVertexAttribArray_State(index);
|
||||
}
|
||||
void DeleteVertexArrays(GLsizei n, const GLuint* arrays) {
|
||||
DeleteVertexArrays_State(n, arrays);
|
||||
}
|
||||
|
||||
void EnableVertexAttribArray(GLuint index) {
|
||||
EnableVertexAttribArray_State(index);
|
||||
}
|
||||
|
||||
void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer) {
|
||||
VertexAttribIPointer_State(index, size, type, stride, pointer);
|
||||
}
|
||||
|
||||
void VertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
|
||||
const void* pointer) {
|
||||
VertexAttribPointer_State(index, size, type, normalized, stride, pointer);
|
||||
}
|
||||
|
||||
void BindVertexArray(GLuint array) {
|
||||
BindVertexArray_State(array);
|
||||
}
|
||||
|
||||
void DeleteVertexArrays(GLsizei n, const GLuint* arrays) {
|
||||
DeleteVertexArrays_State(n, arrays);
|
||||
}
|
||||
|
||||
void GenVertexArrays(GLsizei n, GLuint* arrays) {
|
||||
GenVertexArrays_State(n, arrays);
|
||||
}
|
||||
} // namespace MG_Impl::GLImpl
|
||||
} // namespace MobileGL
|
||||
void GenVertexArrays(GLsizei n, GLuint* arrays) {
|
||||
GenVertexArrays_State(n, arrays);
|
||||
}
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -9,18 +9,16 @@
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void VertexAttribDivisor(GLuint index, GLuint divisor);
|
||||
GLboolean IsVertexArray(GLuint array);
|
||||
void DisableVertexAttribArray(GLuint index);
|
||||
void EnableVertexAttribArray(GLuint index);
|
||||
void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer);
|
||||
void VertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
|
||||
const void* pointer);
|
||||
void BindVertexArray(GLuint array);
|
||||
void DeleteVertexArrays(GLsizei n, const GLuint* arrays);
|
||||
void GenVertexArrays(GLsizei n, GLuint* arrays);
|
||||
} // namespace MG_Impl::GLImpl
|
||||
} // namespace MobileGL
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
|
||||
void VertexAttribDivisor(GLuint index, GLuint divisor);
|
||||
GLboolean IsVertexArray(GLuint array);
|
||||
void DisableVertexAttribArray(GLuint index);
|
||||
void EnableVertexAttribArray(GLuint index);
|
||||
void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer);
|
||||
void VertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
|
||||
const void* pointer);
|
||||
void BindVertexArray(GLuint array);
|
||||
void DeleteVertexArrays(GLsizei n, const GLuint* arrays);
|
||||
void GenVertexArrays(GLsizei n, GLuint* arrays);
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -12,74 +12,71 @@
|
||||
#include <MG_Util/Converters/MGToGL/DataTypeConverter.h>
|
||||
#include <MG_Util/Converters/MGToStr/DataTypeConverter.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
namespace VertexArrayImpl {
|
||||
namespace MobileGL::MG_Impl::GLImpl::VertexArrayImpl {
|
||||
Bool ValidateVertexArrayName(Uint index) {
|
||||
Bool isValid = MG_State::pGLContext->ValidateVertexArrayName(index);
|
||||
if (!isValid) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateVertexArrayName",
|
||||
std::format("Vertex array name {} is not valid.", index)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateVertexArrayName(Uint index) {
|
||||
Bool isValid = MG_State::pGLContext->ValidateVertexArrayName(index);
|
||||
if (!isValid) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateVertexArrayName",
|
||||
std::format("Vertex array name {} is not valid.", index)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
Bool ValidateVertexArrayObject(Uint index) {
|
||||
if (!MG_State::pGLContext->ValidateVertexArrayObject(index)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateVertexArrayObject",
|
||||
std::format("Vertex array object {} does not exist.", index)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateVertexAttributeIndex(Uint index) {
|
||||
if (index >= MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "ValidateVertexAttributeIndex",
|
||||
std::format("Attribute index {} exceeds maximum of {}.", index,
|
||||
MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS - 1)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool ValidateVertexAttribPointerParams(Uint index, SizeT size, DataType type, Int stride) {
|
||||
if (size < 1 || size > 4) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "ValidateVertexAttribPointerParams",
|
||||
std::format("Invalid size {} for attribute {}. Must be 1-4.", size, index)));
|
||||
return false;
|
||||
}
|
||||
|
||||
Bool ValidateVertexArrayObject(Uint index) {
|
||||
if (!MG_State::pGLContext->ValidateVertexArrayObject(index)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateVertexArrayObject",
|
||||
std::format("Vertex array object {} does not exist.", index)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
if (type == DataType::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "ValidateVertexAttribPointerParams",
|
||||
std::format("Invalid type {} for attribute {}.", MG_Util::ConvertDataTypeToString(type), index)));
|
||||
return false;
|
||||
}
|
||||
|
||||
Bool ValidateVertexAttributeIndex(Uint index) {
|
||||
if (index >= MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "ValidateVertexAttributeIndex",
|
||||
std::format("Attribute index {} exceeds maximum of {}.", index,
|
||||
MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS - 1)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
if (stride < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "ValidateVertexAttribPointerParams",
|
||||
std::format("Negative stride {} is not allowed for attribute {}.", stride, index)));
|
||||
return false;
|
||||
}
|
||||
|
||||
Bool ValidateVertexAttribPointerParams(Uint index, SizeT size, DataType type, Int stride) {
|
||||
if (size < 1 || size > 4) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "ValidateVertexAttribPointerParams",
|
||||
std::format("Invalid size {} for attribute {}. Must be 1-4.", size, index)));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == DataType::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeShared<GenericErrorInfo>("MG_Impl/GLImpl", "ValidateVertexAttribPointerParams",
|
||||
std::format("Invalid type {} for attribute {}.",
|
||||
MG_Util::ConvertDataTypeToString(type).c_str(), index)));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stride < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeShared<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "ValidateVertexAttribPointerParams",
|
||||
std::format("Negative stride {} is not allowed for attribute {}.", stride, index)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace VertexArrayImpl
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
return true;
|
||||
}
|
||||
} // namespace MobileGL::MG_Impl::GLImpl::VertexArrayImpl
|
||||
|
||||
@@ -10,11 +10,9 @@
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/VertexArrayState/VertexArrayObject.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
namespace VertexArrayImpl {
|
||||
Bool ValidateVertexArrayName(Uint index);
|
||||
Bool ValidateVertexArrayObject(Uint index);
|
||||
Bool ValidateVertexAttributeIndex(Uint index);
|
||||
Bool ValidateVertexAttribPointerParams(Uint index, SizeT size, DataType type, Int stride);
|
||||
} // namespace VertexArrayImpl
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
namespace MobileGL::MG_Impl::GLImpl::VertexArrayImpl {
|
||||
Bool ValidateVertexArrayName(Uint index);
|
||||
Bool ValidateVertexArrayObject(Uint index);
|
||||
Bool ValidateVertexAttributeIndex(Uint index);
|
||||
Bool ValidateVertexAttribPointerParams(Uint index, SizeT size, DataType type, Int stride);
|
||||
} // namespace MobileGL::MG_Impl::GLImpl::VertexArrayImpl
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
#include <Includes.h>
|
||||
#include "MG_Impl/GetProcAddress.h"
|
||||
|
||||
namespace MG_Impl {
|
||||
namespace GLXImpl {
|
||||
void* GetProcAddress(const char* name);
|
||||
void* GetProcAddressARB(const char* name);
|
||||
} // namespace GLXImpl
|
||||
} // namespace MG_Impl
|
||||
namespace MG_Impl::GLXImpl {
|
||||
void* GetProcAddress(const char* name);
|
||||
void* GetProcAddressARB(const char* name);
|
||||
} // namespace MG_Impl::GLXImpl
|
||||
|
||||
+1338
-1340
File diff suppressed because it is too large
Load Diff
@@ -9,8 +9,6 @@
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Impl {
|
||||
void* GetProcAddress(const char* name);
|
||||
} // namespace MG_Impl
|
||||
} // namespace MobileGL
|
||||
namespace MobileGL::MG_Impl {
|
||||
void* GetProcAddress(const char* name);
|
||||
} // namespace MobileGL::MG_Impl
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
namespace MobileGL::MG_Impl {
|
||||
void Init() {
|
||||
MGLOG_D("Initializing MobileGL Implementation...");
|
||||
GLImpl::TextureImpl::pProxyTextureManager = new GLImpl::TextureImpl::ProxyTextureManager();
|
||||
GLImpl::TextureImpl::pProxyTextureManager = MakeUnique<GLImpl::TextureImpl::ProxyTextureManager>();
|
||||
|
||||
// TODO: get real info in EGL
|
||||
auto fbo0 = MG_State::pGLContext->CreateFramebufferObject(0);
|
||||
auto& fbo0 = MG_State::pGLContext->CreateFramebufferObject(0);
|
||||
auto colorTex = MakeShared<MG_State::GLState::TextureObject2D>(0);
|
||||
colorTex->SetInternalFormat(TextureInternalFormat::RGBA8);
|
||||
colorTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, {{512, 512, 1}, 0});
|
||||
@@ -38,6 +38,8 @@ namespace MobileGL::MG_Impl {
|
||||
fbo0->AttachTexture(FramebufferAttachmentType::Depth, depthTex);
|
||||
fbo0->AttachTexture(FramebufferAttachmentType::Stencil, stencilTex);
|
||||
GLImpl::FramebufferImpl::pDefaultFramebufferInfo =
|
||||
new GLImpl::FramebufferImpl::DefaultFramebufferInfo(fbo0, colorTex, depthTex, stencilTex);
|
||||
MakeUnique<GLImpl::FramebufferImpl::DefaultFramebufferInfo>(fbo0, colorTex, depthTex, stencilTex);
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).Bind(fbo0);
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).Bind(fbo0);
|
||||
}
|
||||
} // namespace MobileGL::MG_Impl
|
||||
|
||||
@@ -16,6 +16,10 @@ namespace MobileGL {
|
||||
constexpr EGLint EGL_DISPLAY_MINOR_VERSION = 5;
|
||||
} // namespace
|
||||
|
||||
Bool EGLContext::DisplayLookupKey::operator==(const DisplayLookupKey& rhs) const {
|
||||
return this->NativeDisplayKey == rhs.NativeDisplayKey && this->Platform == rhs.Platform;
|
||||
}
|
||||
|
||||
SizeT EGLContext::DisplayLookupHasher::operator()(const DisplayLookupKey& key) const {
|
||||
const auto nativeHash = std::hash<Uint64>{}(key.NativeDisplayKey);
|
||||
const auto platformHash = std::hash<Uint64>{}(static_cast<Uint64>(key.Platform));
|
||||
@@ -388,8 +392,6 @@ namespace MobileGL {
|
||||
*value = cfg->SurfaceType;
|
||||
return true;
|
||||
case EGL_RENDERABLE_TYPE:
|
||||
*value = cfg->RenderableType;
|
||||
return true;
|
||||
case EGL_CONFORMANT:
|
||||
*value = cfg->RenderableType;
|
||||
return true;
|
||||
@@ -878,8 +880,8 @@ namespace MobileGL {
|
||||
Bool EGLContext::MakeCurrent(EGLDisplayHandle display, EGLSurfaceHandle draw, EGLSurfaceHandle read,
|
||||
EGLContextHandle context) {
|
||||
const std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||
const Bool releaseCurrentRequest = display == EGL_NO_DISPLAY && draw == EGL_NO_SURFACE &&
|
||||
read == EGL_NO_SURFACE && context == nullptr;
|
||||
const Bool releaseCurrentRequest =
|
||||
display == EGL_NO_DISPLAY && draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE && context == nullptr;
|
||||
const auto threadKey = CurrentThreadKey();
|
||||
if (releaseCurrentRequest) {
|
||||
ReleaseThreadUnlocked(threadKey);
|
||||
@@ -1130,6 +1132,6 @@ namespace MobileGL {
|
||||
}
|
||||
} // namespace EGLState
|
||||
|
||||
EGLState::EGLContext* pEGLContext;
|
||||
UniquePtr<EGLState::EGLContext> pEGLContext;
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace MobileGL {
|
||||
Uint64 NativeDisplayKey = 0;
|
||||
EGLenum Platform = EGL_NONE;
|
||||
|
||||
Bool operator==(const DisplayLookupKey& rhs) const = default;
|
||||
Bool operator==(const DisplayLookupKey& rhs) const;
|
||||
};
|
||||
|
||||
struct DisplayLookupHasher {
|
||||
@@ -253,6 +253,6 @@ namespace MobileGL {
|
||||
};
|
||||
} // namespace EGLState
|
||||
|
||||
extern EGLState::EGLContext* pEGLContext;
|
||||
extern UniquePtr<EGLState::EGLContext> pEGLContext;
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
|
||||
@@ -7,210 +7,203 @@
|
||||
// End of Source File Header
|
||||
|
||||
#include "BufferObject.h"
|
||||
#include "MG_Util/Types.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
BufferObject::BufferObject(Uint externalIndex)
|
||||
: m_externalIndex(externalIndex), m_size(0), m_usage(BufferUsage::StaticDraw), m_isMapped(false),
|
||||
m_mappingAccess(BufferMappingAccessBit::Null),
|
||||
m_change(BufferChangeBits::DirtyBit | BufferChangeBits::PreferReallocationBit), m_mappedRange({0, 0}),
|
||||
m_dataPtr(MakeShared<Data>()) {
|
||||
m_change.DirtyRanges.reserve(BufferChange::DEFAULT_RESERVED_DIRTY_RANGES_COUNT);
|
||||
}
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
BufferObject::BufferObject(Uint externalIndex)
|
||||
: m_externalIndex(externalIndex), m_size(0), m_usage(BufferUsage::StaticDraw), m_isMapped(false),
|
||||
m_mappingAccess(BufferMappingAccessBit::Null),
|
||||
m_change(BufferChangeBits::DirtyBit | BufferChangeBits::PreferReallocationBit), m_mappedRange({0, 0}),
|
||||
m_dataPtr(MakeShared<Data>()), m_ownsStagingData{} {
|
||||
m_change.DirtyRanges.reserve(BufferChange::DEFAULT_RESERVED_DIRTY_RANGES_COUNT);
|
||||
}
|
||||
|
||||
void BufferObject::Resize(SizeT size) {
|
||||
m_size = size;
|
||||
m_dataPtr->reserve(std::bit_ceil(size)); // power-of-2 reserve
|
||||
m_dataPtr->resize(size);
|
||||
void BufferObject::Resize(SizeT size) {
|
||||
m_size = size;
|
||||
m_dataPtr->reserve(std::bit_ceil(size)); // power-of-2 reserve
|
||||
m_dataPtr->resize(size);
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
m_change.Bits |= BufferChangeBits::PreferReallocationBit;
|
||||
}
|
||||
|
||||
void BufferObject::UploadData(DataPtr data, SizeT atOffset) {
|
||||
MOBILEGL_ASSERT(atOffset + data.size <= m_size,
|
||||
"UploadData out of bounds: atOffset (%zu) + data.size (%zu) > m_size (%zu)", atOffset,
|
||||
data.size, m_size);
|
||||
MOBILEGL_ASSERT(!m_isMapped, "Cannot upload data while buffer is mapped.");
|
||||
Memcpy(m_dataPtr->data() + atOffset, data.data, data.size);
|
||||
m_change.DirtyRanges.Add({atOffset, atOffset + data.size});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidInvalidationBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit;
|
||||
// This function may be called by `glBufferData`, but we still set the forbid bits above,
|
||||
// because when `PreferReallocationBit` is set, those bits are ignored anyway.
|
||||
// The bits can fit the `glBufferSubData` semantics
|
||||
// (though `glBufferSubData` calls `UploadSubData` instead).
|
||||
}
|
||||
|
||||
void BufferObject::SetUsage(BufferUsage usage) {
|
||||
m_usage = usage;
|
||||
}
|
||||
|
||||
void BufferObject::ReleaseMemory() {
|
||||
if (!m_isMapped) return;
|
||||
|
||||
if (m_mappingAccess & BufferMappingAccessBit::Write) { // if we wrote to the buffer
|
||||
if (!(m_mappingAccess & BufferMappingAccessBit::FlushExplicit)) { // if we didn't flush explicitly
|
||||
Memcpy(m_dataPtr->data() + m_mappedRange.start, m_stagingData.data(),
|
||||
m_mappedRange.end - m_mappedRange.start);
|
||||
m_change.DirtyRanges.Add({m_mappedRange.start, m_mappedRange.end});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
m_change.Bits |= BufferChangeBits::PreferReallocationBit;
|
||||
}
|
||||
|
||||
void BufferObject::UploadData(DataPtr data, SizeT atOffset) {
|
||||
MOBILEGL_ASSERT(atOffset + data.size <= m_size,
|
||||
"UploadData out of bounds: atOffset (%zu) + data.size (%zu) > m_size (%zu)", atOffset,
|
||||
data.size, m_size);
|
||||
MOBILEGL_ASSERT(!m_isMapped, "Cannot upload data while buffer is mapped.");
|
||||
Memcpy(m_dataPtr->data() + atOffset, data.data, data.size);
|
||||
m_change.DirtyRanges.Add({atOffset, atOffset + data.size});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidInvalidationBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit;
|
||||
// This function may be called by `glBufferData`, but we still set the forbid bits above,
|
||||
// because when `PreferReallocationBit` is set, those bits are ignored anyway.
|
||||
// The bits can fit the `glBufferSubData` semantics
|
||||
// (though `glBufferSubData` calls `UploadSubData` instead).
|
||||
}
|
||||
m_stagingData.clear();
|
||||
}
|
||||
|
||||
void BufferObject::SetUsage(BufferUsage usage) {
|
||||
m_usage = usage;
|
||||
}
|
||||
m_isMapped = false;
|
||||
m_mappingAccess = BufferMappingAccessBit::Null;
|
||||
m_mappedRange = {0, 0};
|
||||
m_ownsStagingData = false;
|
||||
}
|
||||
|
||||
void BufferObject::ReleaseMemory() {
|
||||
if (!m_isMapped) return;
|
||||
void BufferObject::FlushMemoryRange(SizeT offset, SizeT length) {
|
||||
MOBILEGL_ASSERT(m_isMapped, "Buffer must be mapped to flush memory range.");
|
||||
MOBILEGL_ASSERT((m_mappingAccess & BufferMappingAccessBit::FlushExplicit),
|
||||
"Buffer must be mapped with FlushExplicit access to flush memory range.");
|
||||
MOBILEGL_ASSERT((m_mappingAccess & BufferMappingAccessBit::Write),
|
||||
"Buffer must be mapped with Write access to flush memory range.");
|
||||
|
||||
if (m_mappingAccess & BufferMappingAccessBit::Write) { // if we wrote to the buffer
|
||||
if (!(m_mappingAccess & BufferMappingAccessBit::FlushExplicit)) { // if we didn't flush explicitly
|
||||
Memcpy(m_dataPtr->data() + m_mappedRange.start, m_stagingData.data(),
|
||||
m_mappedRange.end - m_mappedRange.start);
|
||||
m_change.DirtyRanges.Add({m_mappedRange.start, m_mappedRange.end});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
}
|
||||
SizeT start = m_mappedRange.start + offset;
|
||||
SizeT end = start + length;
|
||||
MOBILEGL_ASSERT(end <= m_mappedRange.end, "Flush range out of bounds: mappedRange.end (%zu) < end (%zu)",
|
||||
m_mappedRange.end, end);
|
||||
|
||||
m_stagingData.clear();
|
||||
Memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length);
|
||||
m_change.DirtyRanges.Add({start, end});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
}
|
||||
|
||||
void BufferObject::UploadSubData(DataPtr data, SizeT atOffset) {
|
||||
MOBILEGL_ASSERT(!m_isMapped, "Cannot upload sub data while buffer is mapped.");
|
||||
MOBILEGL_ASSERT(atOffset + data.size <= m_size,
|
||||
"UploadSubData out of bounds: atOffset (%zu) + data.size (%zu) > m_size (%zu)", atOffset,
|
||||
data.size, m_size);
|
||||
|
||||
Memcpy(m_dataPtr->data() + atOffset, data.data, data.size);
|
||||
m_change.DirtyRanges.Add({atOffset, atOffset + data.size});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidInvalidationBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit;
|
||||
}
|
||||
|
||||
void BufferObject::CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset, SizeT size) {
|
||||
MOBILEGL_ASSERT(!m_isMapped, "Cannot copy data while buffer is mapped.");
|
||||
MOBILEGL_ASSERT(!src->IsMapped(), "Cannot copy data from a buffer that is mapped.");
|
||||
MOBILEGL_ASSERT(srcOffset + size <= src->GetSize(),
|
||||
"Source buffer copy out of bounds: srcOffset (%zu) + size (%zu) > src->GetSize() (%zu)",
|
||||
srcOffset, size, src->GetSize());
|
||||
MOBILEGL_ASSERT(dstOffset + size <= m_size,
|
||||
"Destination buffer copy out of bounds: dstOffset (%zu) + size (%zu) > m_size (%zu)", dstOffset,
|
||||
size, m_size);
|
||||
|
||||
const Uint8* srcData = src->m_dataPtr->data() + srcOffset;
|
||||
Memcpy(m_dataPtr->data() + dstOffset, srcData, size);
|
||||
m_change.DirtyRanges.Add({dstOffset, dstOffset + size});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
}
|
||||
|
||||
void* BufferObject::AcquireMemory(Bool markMapped, Bool read, Bool write) {
|
||||
if (markMapped) {
|
||||
m_isMapped = true;
|
||||
auto a = BufferMappingAccessBit::Coherent | BufferMappingAccessBit::Read;
|
||||
m_mappingAccess = (read ? BufferMappingAccessBit::Read : BufferMappingAccessBit::Null) |
|
||||
(write ? BufferMappingAccessBit::Write : BufferMappingAccessBit::Null);
|
||||
m_mappedRange = {0, m_size};
|
||||
|
||||
if (m_mappingAccess & BufferMappingAccessBit::Write) {
|
||||
m_stagingData.resize(m_size);
|
||||
m_ownsStagingData = true;
|
||||
|
||||
if (!(m_mappingAccess &
|
||||
(BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer))) {
|
||||
Memcpy(m_stagingData.data(), m_dataPtr->data(), m_size);
|
||||
}
|
||||
|
||||
m_isMapped = false;
|
||||
m_mappingAccess = BufferMappingAccessBit::Null;
|
||||
m_mappedRange = {0, 0};
|
||||
m_ownsStagingData = false;
|
||||
return m_stagingData.data();
|
||||
}
|
||||
}
|
||||
|
||||
return m_dataPtr->data();
|
||||
}
|
||||
|
||||
void* BufferObject::AcquireMemoryRange(Range1D range, Flags<BufferMappingAccessBit> access) {
|
||||
MOBILEGL_ASSERT(range.end <= m_size && range.start <= range.end,
|
||||
"AcquireMemoryRange out of bounds: range (%zu, %zu) exceeds m_size (%zu)", range.start,
|
||||
range.end, m_size);
|
||||
m_isMapped = true;
|
||||
m_mappingAccess = access;
|
||||
m_mappedRange = range;
|
||||
|
||||
if (access & BufferMappingAccessBit::Write) {
|
||||
m_stagingData.resize(range.end - range.start);
|
||||
m_ownsStagingData = true;
|
||||
|
||||
if (!(access & (BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer))) {
|
||||
Memcpy(m_stagingData.data(), m_dataPtr->data() + range.start, m_stagingData.size());
|
||||
}
|
||||
|
||||
void BufferObject::FlushMemoryRange(SizeT offset, SizeT length) {
|
||||
MOBILEGL_ASSERT(m_isMapped, "Buffer must be mapped to flush memory range.");
|
||||
MOBILEGL_ASSERT((m_mappingAccess & BufferMappingAccessBit::FlushExplicit),
|
||||
"Buffer must be mapped with FlushExplicit access to flush memory range.");
|
||||
MOBILEGL_ASSERT((m_mappingAccess & BufferMappingAccessBit::Write),
|
||||
"Buffer must be mapped with Write access to flush memory range.");
|
||||
return m_stagingData.data();
|
||||
} else {
|
||||
m_ownsStagingData = false;
|
||||
return m_dataPtr->data() + range.start;
|
||||
}
|
||||
|
||||
SizeT start = m_mappedRange.start + offset;
|
||||
SizeT end = start + length;
|
||||
MOBILEGL_ASSERT(end <= m_mappedRange.end,
|
||||
"Flush range out of bounds: mappedRange.end (%zu) < end (%zu)", m_mappedRange.end, end);
|
||||
m_change.Bits |=
|
||||
!(access & BufferMappingAccessBit::InvalidateBuffer || access & BufferMappingAccessBit::InvalidateRange)
|
||||
? BufferChangeBits::ForbidInvalidationBit
|
||||
: BufferChangeBits::None;
|
||||
m_change.Bits |= !(access & BufferMappingAccessBit::Unsynchronized)
|
||||
? BufferChangeBits::ForbidUnsynchronizationBit
|
||||
: BufferChangeBits::None;
|
||||
}
|
||||
|
||||
Memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length);
|
||||
m_change.DirtyRanges.Add({start, end});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
}
|
||||
const SharedPtr<Data>& BufferObject::GetDataReadOnly() const {
|
||||
return m_dataPtr;
|
||||
}
|
||||
|
||||
void BufferObject::UploadSubData(DataPtr data, SizeT atOffset) {
|
||||
MOBILEGL_ASSERT(!m_isMapped, "Cannot upload sub data while buffer is mapped.");
|
||||
MOBILEGL_ASSERT(atOffset + data.size <= m_size,
|
||||
"UploadSubData out of bounds: atOffset (%zu) + data.size (%zu) > m_size (%zu)",
|
||||
atOffset, data.size, m_size);
|
||||
void BufferObject::ClearDirty() {
|
||||
m_change.DirtyRanges.clear();
|
||||
m_change.Bits = BufferChangeBits::None;
|
||||
}
|
||||
|
||||
Memcpy(m_dataPtr->data() + atOffset, data.data, data.size);
|
||||
m_change.DirtyRanges.Add({atOffset, atOffset + data.size});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidInvalidationBit;
|
||||
m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit;
|
||||
}
|
||||
SizeT BufferObject::GetSize() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
void BufferObject::CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset,
|
||||
SizeT size) {
|
||||
MOBILEGL_ASSERT(!m_isMapped, "Cannot copy data while buffer is mapped.");
|
||||
MOBILEGL_ASSERT(!src->IsMapped(), "Cannot copy data from a buffer that is mapped.");
|
||||
MOBILEGL_ASSERT(srcOffset + size <= src->GetSize(),
|
||||
"Source buffer copy out of bounds: srcOffset (%zu) + size (%zu) > src->GetSize() (%zu)",
|
||||
srcOffset, size, src->GetSize());
|
||||
MOBILEGL_ASSERT(dstOffset + size <= m_size,
|
||||
"Destination buffer copy out of bounds: dstOffset (%zu) + size (%zu) > m_size (%zu)",
|
||||
dstOffset, size, m_size);
|
||||
BufferUsage BufferObject::GetUsage() const {
|
||||
return m_usage;
|
||||
}
|
||||
|
||||
const Uint8* srcData = src->m_dataPtr->data() + srcOffset;
|
||||
Memcpy(m_dataPtr->data() + dstOffset, srcData, size);
|
||||
m_change.DirtyRanges.Add({dstOffset, dstOffset + size});
|
||||
m_change.Bits |= BufferChangeBits::DirtyBit;
|
||||
}
|
||||
const VecRange1D& BufferObject::GetDirtyRanges() const {
|
||||
return m_change.DirtyRanges;
|
||||
}
|
||||
|
||||
void* BufferObject::AcquireMemory(Bool markMapped, Bool read, Bool write) {
|
||||
if (markMapped) {
|
||||
m_isMapped = true;
|
||||
auto a = BufferMappingAccessBit::Coherent | BufferMappingAccessBit::Read;
|
||||
m_mappingAccess = (read ? BufferMappingAccessBit::Read : BufferMappingAccessBit::Null) |
|
||||
(write ? BufferMappingAccessBit::Write : BufferMappingAccessBit::Null);
|
||||
m_mappedRange = {0, m_size};
|
||||
Flags<BufferChangeBits> BufferObject::GetChangeBits() const {
|
||||
return m_change.Bits;
|
||||
}
|
||||
|
||||
if (m_mappingAccess & BufferMappingAccessBit::Write) {
|
||||
m_stagingData.resize(m_size);
|
||||
m_ownsStagingData = true;
|
||||
Bool BufferObject::IsMapped() const {
|
||||
return m_isMapped;
|
||||
}
|
||||
|
||||
if (!(m_mappingAccess &
|
||||
(BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer))) {
|
||||
Memcpy(m_stagingData.data(), m_dataPtr->data(), m_size);
|
||||
}
|
||||
Range1D BufferObject::GetMappedRange() const {
|
||||
return m_isMapped ? m_mappedRange : Range1D{0, 0};
|
||||
}
|
||||
|
||||
return m_stagingData.data();
|
||||
}
|
||||
}
|
||||
Flags<BufferMappingAccessBit> BufferObject::GetMappingAccess() const {
|
||||
return m_isMapped ? m_mappingAccess : BufferMappingAccessBit::Null;
|
||||
}
|
||||
|
||||
return m_dataPtr->data();
|
||||
}
|
||||
|
||||
void* BufferObject::AcquireMemoryRange(Range1D range, Flags<BufferMappingAccessBit> access) {
|
||||
MOBILEGL_ASSERT(range.end <= m_size && range.start <= range.end,
|
||||
"AcquireMemoryRange out of bounds: range (%zu, %zu) exceeds m_size (%zu)", range.start,
|
||||
range.end, m_size);
|
||||
m_isMapped = true;
|
||||
m_mappingAccess = access;
|
||||
m_mappedRange = range;
|
||||
|
||||
if (access & BufferMappingAccessBit::Write) {
|
||||
m_stagingData.resize(range.end - range.start);
|
||||
m_ownsStagingData = true;
|
||||
|
||||
if (!(access &
|
||||
(BufferMappingAccessBit::InvalidateRange | BufferMappingAccessBit::InvalidateBuffer))) {
|
||||
Memcpy(m_stagingData.data(), m_dataPtr->data() + range.start, m_stagingData.size());
|
||||
}
|
||||
|
||||
return m_stagingData.data();
|
||||
} else {
|
||||
m_ownsStagingData = false;
|
||||
return m_dataPtr->data() + range.start;
|
||||
}
|
||||
|
||||
m_change.Bits |= !(access & BufferMappingAccessBit::InvalidateBuffer ||
|
||||
access & BufferMappingAccessBit::InvalidateRange)
|
||||
? BufferChangeBits::ForbidInvalidationBit
|
||||
: BufferChangeBits::None;
|
||||
m_change.Bits |= !(access & BufferMappingAccessBit::Unsynchronized)
|
||||
? BufferChangeBits::ForbidUnsynchronizationBit
|
||||
: BufferChangeBits::None;
|
||||
}
|
||||
|
||||
const SharedPtr<Data> BufferObject::GetDataReadOnly() const {
|
||||
return m_dataPtr;
|
||||
}
|
||||
|
||||
void BufferObject::ClearDirty() {
|
||||
m_change.DirtyRanges.clear();
|
||||
m_change.Bits = BufferChangeBits::None;
|
||||
}
|
||||
|
||||
SizeT BufferObject::GetSize() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
BufferUsage BufferObject::GetUsage() const {
|
||||
return m_usage;
|
||||
}
|
||||
|
||||
const VecRange1D& BufferObject::GetDirtyRanges() const {
|
||||
return m_change.DirtyRanges;
|
||||
}
|
||||
|
||||
Flags<BufferChangeBits> BufferObject::GetChangeBits() const {
|
||||
return m_change.Bits;
|
||||
}
|
||||
|
||||
Bool BufferObject::IsMapped() const {
|
||||
return m_isMapped;
|
||||
}
|
||||
|
||||
Range1D BufferObject::GetMappedRange() const {
|
||||
return m_isMapped ? m_mappedRange : Range1D{0, 0};
|
||||
}
|
||||
|
||||
Flags<BufferMappingAccessBit> BufferObject::GetMappingAccess() const {
|
||||
return m_isMapped ? m_mappingAccess : BufferMappingAccessBit::Null;
|
||||
}
|
||||
|
||||
Uint BufferObject::GetExternalIndex() const {
|
||||
return m_externalIndex;
|
||||
}
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
Uint BufferObject::GetExternalIndex() const {
|
||||
return m_externalIndex;
|
||||
}
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
#include "MG_Util/Types.h"
|
||||
#include <Includes.h>
|
||||
#include <MG_Util/Math/VectorTypes.h>
|
||||
|
||||
@@ -73,47 +72,45 @@ namespace MobileGL {
|
||||
VecRange1D DirtyRanges;
|
||||
};
|
||||
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
class BufferObject {
|
||||
public:
|
||||
using TargetEnum = BufferTarget;
|
||||
namespace MG_State::GLState {
|
||||
class BufferObject {
|
||||
public:
|
||||
using TargetEnum = BufferTarget;
|
||||
|
||||
BufferObject(Uint externalIndex);
|
||||
BufferObject(Uint externalIndex);
|
||||
|
||||
void Resize(SizeT size);
|
||||
void UploadData(DataPtr data, SizeT atOffset);
|
||||
void SetUsage(BufferUsage usage);
|
||||
void* AcquireMemory(Bool markMapped, Bool read, Bool write);
|
||||
void* AcquireMemoryRange(Range1D range, Flags<BufferMappingAccessBit> access);
|
||||
void ReleaseMemory();
|
||||
void FlushMemoryRange(SizeT offset, SizeT length);
|
||||
void UploadSubData(DataPtr data, SizeT atOffset);
|
||||
void CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset, SizeT size);
|
||||
void ClearDirty();
|
||||
void Resize(SizeT size);
|
||||
void UploadData(DataPtr data, SizeT atOffset);
|
||||
void SetUsage(BufferUsage usage);
|
||||
void* AcquireMemory(Bool markMapped, Bool read, Bool write);
|
||||
void* AcquireMemoryRange(Range1D range, Flags<BufferMappingAccessBit> access);
|
||||
void ReleaseMemory();
|
||||
void FlushMemoryRange(SizeT offset, SizeT length);
|
||||
void UploadSubData(DataPtr data, SizeT atOffset);
|
||||
void CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset, SizeT size);
|
||||
void ClearDirty();
|
||||
|
||||
Bool IsMapped() const;
|
||||
SizeT GetSize() const;
|
||||
BufferUsage GetUsage() const;
|
||||
Range1D GetMappedRange() const;
|
||||
const SharedPtr<Data> GetDataReadOnly() const;
|
||||
Flags<BufferMappingAccessBit> GetMappingAccess() const;
|
||||
Uint GetExternalIndex() const;
|
||||
const VecRange1D& GetDirtyRanges() const;
|
||||
Flags<BufferChangeBits> GetChangeBits() const;
|
||||
Bool IsMapped() const;
|
||||
SizeT GetSize() const;
|
||||
BufferUsage GetUsage() const;
|
||||
Range1D GetMappedRange() const;
|
||||
const SharedPtr<Data>& GetDataReadOnly() const;
|
||||
Flags<BufferMappingAccessBit> GetMappingAccess() const;
|
||||
Uint GetExternalIndex() const;
|
||||
const VecRange1D& GetDirtyRanges() const;
|
||||
Flags<BufferChangeBits> GetChangeBits() const;
|
||||
|
||||
private:
|
||||
const Uint m_externalIndex = 0;
|
||||
SizeT m_size = 0;
|
||||
BufferUsage m_usage = BufferUsage::StaticDraw;
|
||||
SharedPtr<Data> m_dataPtr;
|
||||
Bool m_isMapped;
|
||||
Flags<BufferMappingAccessBit> m_mappingAccess;
|
||||
BufferChange m_change;
|
||||
Range1D m_mappedRange;
|
||||
Vector<Uint8> m_stagingData;
|
||||
Bool m_ownsStagingData;
|
||||
};
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
private:
|
||||
const Uint m_externalIndex = 0;
|
||||
SizeT m_size = 0;
|
||||
BufferUsage m_usage = BufferUsage::StaticDraw;
|
||||
SharedPtr<Data> m_dataPtr;
|
||||
Bool m_isMapped;
|
||||
Flags<BufferMappingAccessBit> m_mappingAccess;
|
||||
BufferChange m_change;
|
||||
Range1D m_mappedRange;
|
||||
Vector<Uint8> m_stagingData;
|
||||
Bool m_ownsStagingData;
|
||||
};
|
||||
} // namespace MG_State::GLState
|
||||
} // namespace MobileGL
|
||||
|
||||
@@ -8,78 +8,75 @@
|
||||
|
||||
#include "BufferState.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
BufferState::BufferState() : m_indexGenerator(1024, 1) {
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
m_bindingSlots[i] = BindingSlot<BufferObject>(GlobalBufferTargets[i]);
|
||||
}
|
||||
}
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
BufferState::BufferState() : m_indexGenerator(1024, 1) {
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
m_bindingSlots[i] = BindingSlot<BufferObject>(GlobalBufferTargets[i]);
|
||||
}
|
||||
}
|
||||
|
||||
SharedPtr<BufferObject> BufferState::GetBufferObject(Uint index) {
|
||||
auto it = m_bufferObjects.find(index);
|
||||
if (it != m_bufferObjects.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
const SharedPtr<BufferObject>& BufferState::GetBufferObject(Uint index) {
|
||||
auto it = m_bufferObjects.find(index);
|
||||
if (it != m_bufferObjects.end()) {
|
||||
return it->second;
|
||||
}
|
||||
static SharedPtr<BufferObject> nullBufferObject = nullptr;
|
||||
return nullBufferObject;
|
||||
}
|
||||
|
||||
Vector<Uint> BufferState::GenerateNames(Uint number) {
|
||||
Vector<Uint> buffers(number);
|
||||
m_indexGenerator.Generate(number, buffers.data());
|
||||
return buffers;
|
||||
}
|
||||
void BufferState::GenerateNames(Uint number, Vector<Uint>& buffers) {
|
||||
buffers.resize(number);
|
||||
m_indexGenerator.Generate(number, buffers.data());
|
||||
}
|
||||
|
||||
SharedPtr<BufferObject> BufferState::CreateBufferObject(Uint index) {
|
||||
auto bufferObject = MakeShared<BufferObject>(index);
|
||||
m_bufferObjects[index] = bufferObject;
|
||||
return bufferObject;
|
||||
}
|
||||
const SharedPtr<BufferObject>& BufferState::CreateBufferObject(Uint index) {
|
||||
auto& bufferObj = m_bufferObjects[index];
|
||||
if (!bufferObj) {
|
||||
bufferObj = MakeShared<BufferObject>(index);
|
||||
}
|
||||
return bufferObj;
|
||||
}
|
||||
|
||||
BindingSlot<BufferObject>& BufferState::GetBindingSlot(BufferTarget target) {
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
if (m_bindingSlots[i].GetTarget() == target) {
|
||||
return m_bindingSlots[i];
|
||||
BindingSlot<BufferObject>& BufferState::GetBindingSlot(BufferTarget target) {
|
||||
for (auto& bindingSlot : m_bindingSlots) {
|
||||
if (bindingSlot.GetTarget() == target) {
|
||||
return bindingSlot;
|
||||
}
|
||||
}
|
||||
MOBILEGL_ASSERT(false, "Invalid BufferTarget enum value: %d", static_cast<int>(target));
|
||||
return m_bindingSlots[0];
|
||||
}
|
||||
|
||||
void BufferState::MarkBufferObjectForDeletion(Uint index) {
|
||||
if (m_indexGenerator.IsValid(index)) {
|
||||
auto it = m_bufferObjects.find(index);
|
||||
if (it != m_bufferObjects.end()) {
|
||||
for (auto& bindingSlot : m_bindingSlots) {
|
||||
if (bindingSlot.GetBoundObject() == it->second) {
|
||||
bindingSlot.Bind(nullptr);
|
||||
}
|
||||
}
|
||||
MOBILEGL_ASSERT(false, "Invalid BufferTarget enum value: %d", static_cast<int>(target));
|
||||
return m_bindingSlots[0];
|
||||
m_bufferObjects.erase(it);
|
||||
}
|
||||
m_indexGenerator.Delete(index);
|
||||
}
|
||||
}
|
||||
|
||||
void BufferState::MarkBufferObjectForDeletion(Uint index) {
|
||||
if (m_indexGenerator.IsValid(index)) {
|
||||
auto it = m_bufferObjects.find(index);
|
||||
if (it != m_bufferObjects.end()) {
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
if (m_bindingSlots[i].GetBoundObject() == it->second) {
|
||||
m_bindingSlots[i].Bind(nullptr);
|
||||
}
|
||||
}
|
||||
m_bufferObjects.erase(it);
|
||||
}
|
||||
m_indexGenerator.Delete(index);
|
||||
}
|
||||
}
|
||||
Bool BufferState::ValidateName(Uint index) const {
|
||||
return m_indexGenerator.IsValid(index);
|
||||
}
|
||||
|
||||
Bool BufferState::ValidateName(Uint index) const {
|
||||
return m_indexGenerator.IsValid(index);
|
||||
}
|
||||
Bool BufferState::ValidateBufferObject(Uint index) const {
|
||||
return m_bufferObjects.find(index) != m_bufferObjects.end();
|
||||
}
|
||||
|
||||
Bool BufferState::ValidateBufferObject(Uint index) const {
|
||||
return m_bufferObjects.find(index) != m_bufferObjects.end();
|
||||
BindingSlotRange1D<BufferObject>& BufferState::GetBindingPoint(BufferTarget target, Uint index) {
|
||||
for (SizeT i = 0; i < BufferBindPointTargets.size(); ++i) {
|
||||
if (BufferBindPointTargets[i] == target) {
|
||||
return m_bufferBindPointTargets[i][index];
|
||||
}
|
||||
|
||||
BindingSlotRange1D<BufferObject>& BufferState::GetBindingPoint(BufferTarget target, Uint index) {
|
||||
for (SizeT i = 0; i < BufferBindPointTargets.size(); ++i) {
|
||||
if (BufferBindPointTargets[i] == target) {
|
||||
return m_bufferBindPointTargets[i][index];
|
||||
}
|
||||
}
|
||||
MOBILEGL_ASSERT(false, "Invalid BufferTarget enum value for binding point: %d",
|
||||
static_cast<int>(target));
|
||||
return m_bufferBindPointTargets[0][index];
|
||||
}
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
}
|
||||
MOBILEGL_ASSERT(false, "Invalid BufferTarget enum value for binding point: %d", static_cast<int>(target));
|
||||
return m_bufferBindPointTargets[0][index];
|
||||
}
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -11,46 +11,40 @@
|
||||
#include <MG_Util/Miscellany/IndexGenerator.h>
|
||||
#include "BufferObject.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
constexpr const auto GlobalBufferTargets =
|
||||
ToArray(BufferTarget::Vertex, BufferTarget::Uniform, BufferTarget::CopyRead, BufferTarget::CopyWrite,
|
||||
BufferTarget::PixelPack, BufferTarget::PixelUnpack, BufferTarget::Query, BufferTarget::Texture,
|
||||
BufferTarget::TransformFeedback, BufferTarget::AtomicCounter, BufferTarget::DispatchIndirect,
|
||||
BufferTarget::DrawIndirect, BufferTarget::ShaderStorage);
|
||||
constexpr const auto BufferBindPointTargets =
|
||||
ToArray(BufferTarget::Uniform, BufferTarget::TransformFeedback, BufferTarget::AtomicCounter,
|
||||
BufferTarget::ShaderStorage);
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
constexpr const auto GlobalBufferTargets =
|
||||
ToArray(BufferTarget::Vertex, BufferTarget::Uniform, BufferTarget::CopyRead, BufferTarget::CopyWrite,
|
||||
BufferTarget::PixelPack, BufferTarget::PixelUnpack, BufferTarget::Query, BufferTarget::Texture,
|
||||
BufferTarget::TransformFeedback, BufferTarget::AtomicCounter, BufferTarget::DispatchIndirect,
|
||||
BufferTarget::DrawIndirect, BufferTarget::ShaderStorage);
|
||||
constexpr const auto BufferBindPointTargets = ToArray(BufferTarget::Uniform, BufferTarget::TransformFeedback,
|
||||
BufferTarget::AtomicCounter, BufferTarget::ShaderStorage);
|
||||
|
||||
class BufferState {
|
||||
public:
|
||||
BufferState();
|
||||
class BufferState {
|
||||
public:
|
||||
BufferState();
|
||||
|
||||
SharedPtr<BufferObject> GetBufferObject(Uint index);
|
||||
Vector<Uint> GenerateNames(Uint number);
|
||||
SharedPtr<BufferObject> CreateBufferObject(Uint index);
|
||||
BindingSlot<BufferObject>& GetBindingSlot(BufferTarget target);
|
||||
// For glBindBufferBase / glBindBufferRange
|
||||
BindingSlotRange1D<BufferObject>& GetBindingPoint(BufferTarget target, Uint index);
|
||||
constexpr SizeT GetBindingPointCount(const BufferTarget target) const {
|
||||
auto it = std::find(BufferBindPointTargets.begin(), BufferBindPointTargets.end(), target);
|
||||
auto index = std::distance(BufferBindPointTargets.begin(), it);
|
||||
return m_bufferBindPointTargets[index].size();
|
||||
}
|
||||
void MarkBufferObjectForDeletion(Uint index);
|
||||
Bool ValidateName(Uint index) const;
|
||||
Bool ValidateBufferObject(Uint index) const;
|
||||
const SharedPtr<BufferObject>& GetBufferObject(Uint index);
|
||||
void GenerateNames(Uint number, Vector<Uint>& buffers);
|
||||
const SharedPtr<BufferObject>& CreateBufferObject(Uint index);
|
||||
BindingSlot<BufferObject>& GetBindingSlot(BufferTarget target);
|
||||
// For glBindBufferBase / glBindBufferRange
|
||||
BindingSlotRange1D<BufferObject>& GetBindingPoint(BufferTarget target, Uint index);
|
||||
constexpr SizeT GetBindingPointCount(const BufferTarget target) const {
|
||||
auto it = std::find(BufferBindPointTargets.begin(), BufferBindPointTargets.end(), target);
|
||||
auto index = std::distance(BufferBindPointTargets.begin(), it);
|
||||
return m_bufferBindPointTargets[index].size();
|
||||
}
|
||||
void MarkBufferObjectForDeletion(Uint index);
|
||||
Bool ValidateName(Uint index) const;
|
||||
Bool ValidateBufferObject(Uint index) const;
|
||||
|
||||
private:
|
||||
UnorderedMap<Uint, SharedPtr<BufferObject>> m_bufferObjects;
|
||||
IndexGenerator<Uint> m_indexGenerator;
|
||||
Array<BindingSlot<BufferObject>, GlobalBufferTargets.size()> m_bindingSlots;
|
||||
// TODO: query the count somewhere globally?
|
||||
// For glBindBufferBase / glBindBufferRange
|
||||
Array<Array<BindingSlotRange1D<BufferObject>, 16>, BufferBindPointTargets.size()>
|
||||
m_bufferBindPointTargets;
|
||||
};
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
private:
|
||||
UnorderedMap<Uint, SharedPtr<BufferObject>> m_bufferObjects;
|
||||
IndexGenerator<Uint> m_indexGenerator;
|
||||
Array<BindingSlot<BufferObject>, GlobalBufferTargets.size()> m_bindingSlots;
|
||||
// TODO: query the count somewhere globally?
|
||||
// For glBindBufferBase / glBindBufferRange
|
||||
Array<Array<BindingSlotRange1D<BufferObject>, 16>, BufferBindPointTargets.size()> m_bufferBindPointTargets;
|
||||
};
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
+336
-336
@@ -10,436 +10,436 @@
|
||||
#include "MG_State/GLState/RenderbufferState/RenderbufferObject.h"
|
||||
#include "MG_State/EGLState/Core.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
void Init() {
|
||||
MGLOG_D("Initializing MobileGL State...");
|
||||
pGLContext = new MG_State::GLState::GLContext();
|
||||
pEGLContext = new MG_State::EGLState::EGLContext();
|
||||
namespace MobileGL::MG_State {
|
||||
void Init() {
|
||||
MGLOG_D("Initializing MobileGL State...");
|
||||
pGLContext = MakeUnique<GLState::GLContext>();
|
||||
pEGLContext = MakeUnique<EGLState::EGLContext>();
|
||||
}
|
||||
|
||||
namespace GLState {
|
||||
// Error
|
||||
void GLContext::RecordError(ErrorCode code, UniquePtr<ErrorInfo> info) {
|
||||
m_errorState.RecordError(code, Move(info));
|
||||
}
|
||||
|
||||
namespace GLState {
|
||||
// Error
|
||||
void GLContext::RecordError(ErrorCode code, SharedPtr<ErrorInfo> info) {
|
||||
m_errorState.RecordError(code, info);
|
||||
Bool GLContext::HasGLError() const {
|
||||
return m_errorState.HasGLError();
|
||||
}
|
||||
|
||||
Optional<const Error*> GLContext::PeekGLError() const {
|
||||
return m_errorState.PeekGLError();
|
||||
}
|
||||
|
||||
Optional<UniquePtr<Error>> GLContext::PopGLError() {
|
||||
return Move(m_errorState.PopGLError());
|
||||
}
|
||||
|
||||
Bool GLContext::HasNonGLError() const {
|
||||
return m_errorState.HasNonGLError();
|
||||
}
|
||||
|
||||
Optional<const Error*> GLContext::PeekNonGLError() const {
|
||||
return m_errorState.PeekNonGLError();
|
||||
}
|
||||
|
||||
Optional<UniquePtr<Error>> GLContext::PopNonGLError() {
|
||||
return Move(m_errorState.PopNonGLError());
|
||||
}
|
||||
|
||||
void GLContext::ClearErrors() {
|
||||
m_errorState.Clear();
|
||||
}
|
||||
|
||||
// Buffer
|
||||
void GLContext::GenBufferNames(Uint number, Vector<Uint>& buffers) {
|
||||
m_bufferState.GenerateNames(number, buffers);
|
||||
}
|
||||
|
||||
const SharedPtr<BufferObject>& GLContext::GetBufferObject(Uint index) {
|
||||
return m_bufferState.GetBufferObject(index);
|
||||
}
|
||||
|
||||
BindingSlot<BufferObject>& GLContext::GetBufferBindingSlot(BufferTarget target) {
|
||||
if (target == BufferTarget::Index) {
|
||||
const auto& vao = m_vertexArrayState.GetBoundVertexArray();
|
||||
MOBILEGL_ASSERT(vao != nullptr, "No VAO is currently bound when accessing index buffer binding slot.");
|
||||
return vao->GetIndexBufferBindingSlot();
|
||||
}
|
||||
|
||||
Bool GLContext::HasGLError() const {
|
||||
return m_errorState.HasGLError();
|
||||
}
|
||||
return m_bufferState.GetBindingSlot(target);
|
||||
}
|
||||
|
||||
Optional<const Error> GLContext::PeekGLError() const {
|
||||
return m_errorState.PeekGLError();
|
||||
}
|
||||
BindingSlotRange1D<BufferObject>& GLContext::GetBufferBindingPoint(BufferTarget target, Uint index) {
|
||||
return m_bufferState.GetBindingPoint(target, index);
|
||||
}
|
||||
|
||||
Optional<Error> GLContext::PopGLError() {
|
||||
return m_errorState.PopGLError();
|
||||
}
|
||||
const SharedPtr<BufferObject>& GLContext::CreateBufferObject(Uint index) {
|
||||
return m_bufferState.CreateBufferObject(index);
|
||||
}
|
||||
|
||||
Bool GLContext::HasNonGLError() const {
|
||||
return m_errorState.HasNonGLError();
|
||||
}
|
||||
void GLContext::MarkBufferObjectForDeletion(Uint index) {
|
||||
if (ValidateBufferObject(index)) {
|
||||
auto bufferObject = m_bufferState.GetBufferObject(index);
|
||||
auto& vaos = m_vertexArrayState.GetAllVertexArrays();
|
||||
for (auto& vao : vaos) {
|
||||
if (vao == nullptr) continue;
|
||||
|
||||
Optional<const Error> GLContext::PeekNonGLError() const {
|
||||
return m_errorState.PeekNonGLError();
|
||||
}
|
||||
|
||||
Optional<Error> GLContext::PopNonGLError() {
|
||||
return m_errorState.PopNonGLError();
|
||||
}
|
||||
|
||||
void GLContext::ClearErrors() {
|
||||
m_errorState.Clear();
|
||||
}
|
||||
|
||||
// Buffer
|
||||
Vector<Uint> GLContext::GenBufferNames(Uint number) {
|
||||
return m_bufferState.GenerateNames(number);
|
||||
}
|
||||
|
||||
SharedPtr<BufferObject> GLContext::GetBufferObject(Uint index) {
|
||||
return m_bufferState.GetBufferObject(index);
|
||||
}
|
||||
|
||||
BindingSlot<BufferObject>& GLContext::GetBufferBindingSlot(BufferTarget target) {
|
||||
if (target == BufferTarget::Index) {
|
||||
const auto& vao = m_vertexArrayState.GetBoundVertexArray();
|
||||
MOBILEGL_ASSERT(vao != nullptr,
|
||||
"No VAO is currently bound when accessing index buffer binding slot.");
|
||||
return vao->GetIndexBufferBindingSlot();
|
||||
}
|
||||
|
||||
return m_bufferState.GetBindingSlot(target);
|
||||
}
|
||||
|
||||
BindingSlotRange1D<BufferObject>& GLContext::GetBufferBindingPoint(BufferTarget target, Uint index) {
|
||||
return m_bufferState.GetBindingPoint(target, index);
|
||||
}
|
||||
|
||||
SharedPtr<BufferObject> GLContext::CreateBufferObject(Uint index) {
|
||||
return m_bufferState.CreateBufferObject(index);
|
||||
}
|
||||
|
||||
void GLContext::MarkBufferObjectForDeletion(Uint index) {
|
||||
if (ValidateBufferObject(index)) {
|
||||
auto bufferObject = m_bufferState.GetBufferObject(index);
|
||||
auto& vaos = m_vertexArrayState.GetAllVertexArrays();
|
||||
for (SizeT i = 0; i < vaos.size(); ++i) {
|
||||
auto vao = vaos[i];
|
||||
if (vao == nullptr) continue;
|
||||
|
||||
if (vao->GetIndexBufferBindingSlot().GetBoundObject() == bufferObject) {
|
||||
vao->GetIndexBufferBindingSlot().Bind(nullptr);
|
||||
}
|
||||
for (SizeT j = 0; j < VertexArrayObject::MAX_VERTEX_ATTRIBS; ++j) {
|
||||
if (vao->GetAttribute(j).Buffer == bufferObject) {
|
||||
vao->BindAttributeBuffer(j, nullptr);
|
||||
}
|
||||
if (vao->GetIndexBufferBindingSlot().GetBoundObject() == bufferObject) {
|
||||
vao->GetIndexBufferBindingSlot().Bind(nullptr);
|
||||
}
|
||||
for (SizeT j = 0; j < VertexArrayObject::MAX_VERTEX_ATTRIBS; ++j) {
|
||||
if (vao->GetAttribute(j).Buffer == bufferObject) {
|
||||
vao->BindAttributeBuffer(j, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_bufferState.MarkBufferObjectForDeletion(index);
|
||||
}
|
||||
|
||||
Bool GLContext::ValidateBufferName(Uint index) const {
|
||||
return m_bufferState.ValidateName(index);
|
||||
}
|
||||
m_bufferState.MarkBufferObjectForDeletion(index);
|
||||
}
|
||||
|
||||
Bool GLContext::ValidateBufferObject(Uint index) const {
|
||||
return m_bufferState.ValidateBufferObject(index);
|
||||
}
|
||||
Bool GLContext::ValidateBufferName(Uint index) const {
|
||||
return m_bufferState.ValidateName(index);
|
||||
}
|
||||
|
||||
// VertexArray
|
||||
Vector<Uint> GLContext::GenVertexArrayNames(Uint number) {
|
||||
return m_vertexArrayState.GenerateNames(number);
|
||||
}
|
||||
Bool GLContext::ValidateBufferObject(Uint index) const {
|
||||
return m_bufferState.ValidateBufferObject(index);
|
||||
}
|
||||
|
||||
SharedPtr<VertexArrayObject> GLContext::GetVertexArrayObject(Uint index) {
|
||||
return m_vertexArrayState.GetVertexArrayObject(index);
|
||||
}
|
||||
// VertexArray
|
||||
void GLContext::GenVertexArrayNames(Uint number, Vector<Uint>& vertexArrays) {
|
||||
m_vertexArrayState.GenerateNames(number, vertexArrays);
|
||||
}
|
||||
|
||||
void GLContext::BindVertexArray(Uint index) {
|
||||
m_vertexArrayState.Bind(index);
|
||||
}
|
||||
const SharedPtr<VertexArrayObject>& GLContext::GetVertexArrayObject(Uint index) {
|
||||
return m_vertexArrayState.GetVertexArrayObject(index);
|
||||
}
|
||||
|
||||
SharedPtr<VertexArrayObject> GLContext::CreateVertexArrayObject(Uint index) {
|
||||
return m_vertexArrayState.CreateVertexArrayObject(index);
|
||||
}
|
||||
void GLContext::BindVertexArray(Uint index) {
|
||||
m_vertexArrayState.Bind(index);
|
||||
}
|
||||
|
||||
void GLContext::MarkVertexArrayForDeletion(Uint index) {
|
||||
m_vertexArrayState.MarkVertexArrayForDeletion(index);
|
||||
}
|
||||
const SharedPtr<VertexArrayObject>& GLContext::CreateVertexArrayObject(Uint index) {
|
||||
return m_vertexArrayState.CreateVertexArrayObject(index);
|
||||
}
|
||||
|
||||
Bool GLContext::ValidateVertexArrayName(Uint index) const {
|
||||
return m_vertexArrayState.ValidateName(index);
|
||||
}
|
||||
void GLContext::MarkVertexArrayForDeletion(Uint index) {
|
||||
m_vertexArrayState.MarkVertexArrayForDeletion(index);
|
||||
}
|
||||
|
||||
Bool GLContext::ValidateVertexArrayObject(Uint index) const {
|
||||
return m_vertexArrayState.ValidateVertexArrayObject(index);
|
||||
}
|
||||
Bool GLContext::ValidateVertexArrayName(Uint index) const {
|
||||
return m_vertexArrayState.ValidateName(index);
|
||||
}
|
||||
|
||||
SharedPtr<VertexArrayObject> GLContext::GetBoundVertexArray() {
|
||||
return m_vertexArrayState.GetBoundVertexArray();
|
||||
}
|
||||
Bool GLContext::ValidateVertexArrayObject(Uint index) const {
|
||||
return m_vertexArrayState.ValidateVertexArrayObject(index);
|
||||
}
|
||||
|
||||
// Texture
|
||||
Vector<Uint> GLContext::GenTextureNames(Uint number) {
|
||||
return m_textureState.GenerateNames(number);
|
||||
}
|
||||
const SharedPtr<VertexArrayObject>& GLContext::GetBoundVertexArray() {
|
||||
return m_vertexArrayState.GetBoundVertexArray();
|
||||
}
|
||||
|
||||
SharedPtr<ITextureObject> GLContext::GetTextureObject(Uint index) {
|
||||
return m_textureState.GetTextureObject(index);
|
||||
}
|
||||
// Texture
|
||||
void GLContext::GenTextureNames(Uint number, Vector<Uint>& textures) {
|
||||
m_textureState.GenerateNames(number, textures);
|
||||
}
|
||||
|
||||
SharedPtr<ITextureObject> GLContext::CreateTextureObject(Uint index, TextureTarget target) {
|
||||
return m_textureState.CreateTextureObject(index, target);
|
||||
}
|
||||
const SharedPtr<ITextureObject>& GLContext::GetTextureObject(Uint index) {
|
||||
return m_textureState.GetTextureObject(index);
|
||||
}
|
||||
|
||||
void GLContext::MarkTextureObjectForDeletion(Uint index) {
|
||||
m_textureState.MarkTextureObjectForDeletion(index);
|
||||
}
|
||||
const SharedPtr<ITextureObject>& GLContext::CreateTextureObject(Uint index, TextureTarget target) {
|
||||
return m_textureState.CreateTextureObject(index, target);
|
||||
}
|
||||
|
||||
TextureUnit& GLContext::GetTextureUnitObject(Int unit) {
|
||||
return m_textureState.GetUnitObject(unit);
|
||||
}
|
||||
void GLContext::MarkTextureObjectForDeletion(Uint index) {
|
||||
m_textureState.MarkTextureObjectForDeletion(index);
|
||||
}
|
||||
|
||||
Bool GLContext::ValidateTextureName(Uint index) const {
|
||||
return m_textureState.ValidateName(index);
|
||||
}
|
||||
TextureUnit& GLContext::GetTextureUnitObject(Int unit) {
|
||||
return m_textureState.GetUnitObject(unit);
|
||||
}
|
||||
|
||||
Bool GLContext::ValidateTextureObject(Uint index) const {
|
||||
return m_textureState.ValidateTextureObject(index);
|
||||
}
|
||||
Bool GLContext::ValidateTextureName(Uint index) const {
|
||||
return m_textureState.ValidateName(index);
|
||||
}
|
||||
|
||||
Int GLContext::GetActiveTextureUnit() const {
|
||||
return m_textureState.GetActiveTextureUnit();
|
||||
}
|
||||
Bool GLContext::ValidateTextureObject(Uint index) const {
|
||||
return m_textureState.ValidateTextureObject(index);
|
||||
}
|
||||
|
||||
void GLContext::SetActiveTextureUnit(Int unit) {
|
||||
m_textureState.SetActiveTextureUnit(unit);
|
||||
}
|
||||
Int GLContext::GetActiveTextureUnit() const {
|
||||
return m_textureState.GetActiveTextureUnit();
|
||||
}
|
||||
|
||||
// Program
|
||||
Uint GLContext::CreateProgram() {
|
||||
return m_programState.CreateProgram();
|
||||
}
|
||||
void GLContext::SetActiveTextureUnit(Int unit) {
|
||||
m_textureState.SetActiveTextureUnit(unit);
|
||||
}
|
||||
|
||||
Uint GLContext::CreateShader(const ShaderStage stage) {
|
||||
return m_programState.CreateShader(stage);
|
||||
}
|
||||
// Program
|
||||
Uint GLContext::CreateProgram() {
|
||||
return m_programState.CreateProgram();
|
||||
}
|
||||
|
||||
void GLContext::MarkProgramForDeletion(const Uint index) {
|
||||
return m_programState.MarkProgramObjectForDeletion(index);
|
||||
}
|
||||
Uint GLContext::CreateShader(const ShaderStage stage) {
|
||||
return m_programState.CreateShader(stage);
|
||||
}
|
||||
|
||||
void GLContext::MarkShaderForDeletion(const Uint index) {
|
||||
return m_programState.MarkShaderObjectForDeletion(index);
|
||||
}
|
||||
void GLContext::MarkProgramForDeletion(const Uint index) {
|
||||
return m_programState.MarkProgramObjectForDeletion(index);
|
||||
}
|
||||
|
||||
Bool GLContext::ValidateProgramName(const Uint index) const {
|
||||
return m_programState.ValidateProgramObject(index);
|
||||
}
|
||||
void GLContext::MarkShaderForDeletion(const Uint index) {
|
||||
return m_programState.MarkShaderObjectForDeletion(index);
|
||||
}
|
||||
|
||||
Bool GLContext::ValidateShaderName(const Uint index) const {
|
||||
return m_programState.ValidateShaderObject(index);
|
||||
}
|
||||
Bool GLContext::ValidateProgramName(const Uint index) const {
|
||||
return m_programState.ValidateProgramObject(index);
|
||||
}
|
||||
|
||||
SharedPtr<ProgramObject> GLContext::GetProgramObject(const Uint index) {
|
||||
return m_programState.GetProgramObject(index);
|
||||
}
|
||||
Bool GLContext::ValidateShaderName(const Uint index) const {
|
||||
return m_programState.ValidateShaderObject(index);
|
||||
}
|
||||
|
||||
SharedPtr<ShaderObject> GLContext::GetShaderObject(const Uint index) {
|
||||
return m_programState.GetShaderObject(index);
|
||||
}
|
||||
const SharedPtr<ProgramObject>& GLContext::GetProgramObject(const Uint index) {
|
||||
return m_programState.GetProgramObject(index);
|
||||
}
|
||||
|
||||
void GLContext::UseProgram(Uint program) {
|
||||
return m_programState.UseProgram(program);
|
||||
}
|
||||
const SharedPtr<ShaderObject>& GLContext::GetShaderObject(const Uint index) {
|
||||
return m_programState.GetShaderObject(index);
|
||||
}
|
||||
|
||||
SharedPtr<ProgramObject> GLContext::GetCurrentProgram() {
|
||||
return m_programState.GetCurrentProgram();
|
||||
}
|
||||
void GLContext::UseProgram(Uint program) {
|
||||
return m_programState.UseProgram(program);
|
||||
}
|
||||
|
||||
// RenderState
|
||||
Uint GLContext::GetRenderStateParametersVersion() const {
|
||||
return m_renderState.GetVersion();
|
||||
}
|
||||
const SharedPtr<ProgramObject>& GLContext::GetCurrentProgram() {
|
||||
return m_programState.GetCurrentProgram();
|
||||
}
|
||||
|
||||
const RenderStateParameters& GLContext::GetRenderStateParameters() const {
|
||||
return m_renderState.GetAllParameters();
|
||||
}
|
||||
// RenderState
|
||||
Uint GLContext::GetRenderStateParametersVersion() const {
|
||||
return m_renderState.GetVersion();
|
||||
}
|
||||
|
||||
void GLContext::SetViewport(IntVec4 viewport) {
|
||||
m_renderState.SetViewport(viewport);
|
||||
}
|
||||
const RenderStateParameters& GLContext::GetRenderStateParameters() const {
|
||||
return m_renderState.GetAllParameters();
|
||||
}
|
||||
|
||||
const IntVec4& GLContext::GetViewport() const {
|
||||
return m_renderState.GetViewport();
|
||||
}
|
||||
void GLContext::SetViewport(IntVec4 viewport) {
|
||||
m_renderState.SetViewport(viewport);
|
||||
}
|
||||
|
||||
void GLContext::SetCapability(CapabilityInput cap, Bool enabled) {
|
||||
m_renderState.SetCapability(cap, enabled);
|
||||
}
|
||||
const IntVec4& GLContext::GetViewport() const {
|
||||
return m_renderState.GetViewport();
|
||||
}
|
||||
|
||||
Bool GLContext::IsCapabilityEnabled(CapabilityInput cap) const {
|
||||
return m_renderState.IsCapabilityEnabled(cap);
|
||||
}
|
||||
void GLContext::SetCapability(CapabilityInput cap, Bool enabled) {
|
||||
m_renderState.SetCapability(cap, enabled);
|
||||
}
|
||||
|
||||
void GLContext::SetCapabilityIndexed(CapabilityInput cap, Uint index, Bool enabled) {
|
||||
m_renderState.SetCapabilityIndexed(cap, index, enabled);
|
||||
}
|
||||
Bool GLContext::IsCapabilityEnabled(CapabilityInput cap) const {
|
||||
return m_renderState.IsCapabilityEnabled(cap);
|
||||
}
|
||||
|
||||
Bool GLContext::IsCapabilityEnabledIndexed(CapabilityInput cap, Uint index) const {
|
||||
return m_renderState.IsCapabilityEnabledIndexed(cap, index);
|
||||
}
|
||||
void GLContext::SetCapabilityIndexed(CapabilityInput cap, Uint index, Bool enabled) {
|
||||
m_renderState.SetCapabilityIndexed(cap, index, enabled);
|
||||
}
|
||||
|
||||
void GLContext::SetBlendFunc(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha,
|
||||
BlendFactor dstAlpha) {
|
||||
m_renderState.SetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
Bool GLContext::IsCapabilityEnabledIndexed(CapabilityInput cap, Uint index) const {
|
||||
return m_renderState.IsCapabilityEnabledIndexed(cap, index);
|
||||
}
|
||||
|
||||
void GLContext::GetBlendFunc(BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha,
|
||||
BlendFactor& dstAlpha) const {
|
||||
m_renderState.GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
void GLContext::SetBlendFunc(BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha,
|
||||
BlendFactor dstAlpha) {
|
||||
m_renderState.SetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
|
||||
void GLContext::SetBlendFuncIndexed(Uint index, BlendFactor srcRGB, BlendFactor dstRGB,
|
||||
BlendFactor srcAlpha, BlendFactor dstAlpha) {
|
||||
m_renderState.SetBlendFuncIndexed(index, srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
void GLContext::GetBlendFunc(BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha,
|
||||
BlendFactor& dstAlpha) const {
|
||||
m_renderState.GetBlendFunc(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
|
||||
void GLContext::GetBlendFuncIndexed(Uint index, BlendFactor& srcRGB, BlendFactor& dstRGB,
|
||||
BlendFactor& srcAlpha, BlendFactor& dstAlpha) const {
|
||||
m_renderState.GetBlendFuncIndexed(index, srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
void GLContext::SetBlendFuncIndexed(Uint index, BlendFactor srcRGB, BlendFactor dstRGB, BlendFactor srcAlpha,
|
||||
BlendFactor dstAlpha) {
|
||||
m_renderState.SetBlendFuncIndexed(index, srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
|
||||
void GLContext::SetDepthFunc(DepthTestFunc func) {
|
||||
m_renderState.SetDepthFunc(func);
|
||||
}
|
||||
void GLContext::GetBlendFuncIndexed(Uint index, BlendFactor& srcRGB, BlendFactor& dstRGB, BlendFactor& srcAlpha,
|
||||
BlendFactor& dstAlpha) const {
|
||||
m_renderState.GetBlendFuncIndexed(index, srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
|
||||
DepthTestFunc GLContext::GetDepthFunc() const {
|
||||
return m_renderState.GetDepthFunc();
|
||||
}
|
||||
void GLContext::SetDepthFunc(DepthTestFunc func) {
|
||||
m_renderState.SetDepthFunc(func);
|
||||
}
|
||||
|
||||
void GLContext::SetDepthMask(Bool flag) {
|
||||
m_renderState.SetDepthMask(flag);
|
||||
}
|
||||
DepthTestFunc GLContext::GetDepthFunc() const {
|
||||
return m_renderState.GetDepthFunc();
|
||||
}
|
||||
|
||||
Bool GLContext::GetDepthMask() const {
|
||||
return m_renderState.GetDepthMask();
|
||||
}
|
||||
void GLContext::SetDepthMask(Bool flag) {
|
||||
m_renderState.SetDepthMask(flag);
|
||||
}
|
||||
|
||||
void GLContext::SetColorMask(BoolVec4 mask) {
|
||||
m_renderState.SetColorMask(mask);
|
||||
}
|
||||
Bool GLContext::GetDepthMask() const {
|
||||
return m_renderState.GetDepthMask();
|
||||
}
|
||||
|
||||
const BoolVec4 GLContext::GetColorMask() const {
|
||||
return m_renderState.GetColorMask();
|
||||
}
|
||||
void GLContext::SetColorMask(BoolVec4 mask) {
|
||||
m_renderState.SetColorMask(mask);
|
||||
}
|
||||
|
||||
void GLContext::SetClearColor(FloatVec4 color) {
|
||||
m_renderState.SetClearColor(color);
|
||||
}
|
||||
BoolVec4 GLContext::GetColorMask() const {
|
||||
return m_renderState.GetColorMask();
|
||||
}
|
||||
|
||||
const FloatVec4& GLContext::GetClearColor() const {
|
||||
return m_renderState.GetClearColor();
|
||||
}
|
||||
void GLContext::SetClearColor(FloatVec4 color) {
|
||||
m_renderState.SetClearColor(color);
|
||||
}
|
||||
|
||||
void GLContext::SetClearDepth(Float depth) {
|
||||
m_renderState.SetClearDepth(depth);
|
||||
}
|
||||
const FloatVec4& GLContext::GetClearColor() const {
|
||||
return m_renderState.GetClearColor();
|
||||
}
|
||||
|
||||
Float GLContext::GetClearDepth() const {
|
||||
return m_renderState.GetClearDepth();
|
||||
}
|
||||
void GLContext::SetClearDepth(Float depth) {
|
||||
m_renderState.SetClearDepth(depth);
|
||||
}
|
||||
|
||||
void GLContext::SetClearStencil(Int stencil) {
|
||||
m_renderState.SetClearStencil(stencil);
|
||||
}
|
||||
Float GLContext::GetClearDepth() const {
|
||||
return m_renderState.GetClearDepth();
|
||||
}
|
||||
|
||||
Int GLContext::GetClearStencil() const {
|
||||
void GLContext::SetClearStencil(Int stencil) {
|
||||
m_renderState.SetClearStencil(stencil);
|
||||
}
|
||||
|
||||
Uint32 GLContext::GetClearStencil() const {
|
||||
return m_renderState.GetClearStencil();
|
||||
}
|
||||
|
||||
void GLContext::SetPixelStoreParam(PixelStoreParam param, Int value) {
|
||||
m_renderState.SetPixelStoreParam(param, value);
|
||||
}
|
||||
void GLContext::SetPixelStoreParam(PixelStoreParam param, Int value) {
|
||||
m_renderState.SetPixelStoreParam(param, value);
|
||||
}
|
||||
|
||||
Int GLContext::GetPixelStoreParam(PixelStoreParam param) const {
|
||||
return m_renderState.GetPixelStoreParam(param);
|
||||
}
|
||||
Int GLContext::GetPixelStoreParam(PixelStoreParam param) const {
|
||||
return m_renderState.GetPixelStoreParam(param);
|
||||
}
|
||||
|
||||
PixelStoreParameters GLContext::GetPixelStoreParameters(Bool isUnpack) const {
|
||||
return m_renderState.GetPixelStoreParameters(isUnpack);
|
||||
}
|
||||
PixelStoreParameters GLContext::GetPixelStoreParameters(Bool isUnpack) const {
|
||||
return m_renderState.GetPixelStoreParameters(isUnpack);
|
||||
}
|
||||
|
||||
void GLContext::SetCullFaceMode(CullFaceMode mode) {
|
||||
m_renderState.SetCullFaceMode(mode);
|
||||
}
|
||||
void GLContext::SetCullFaceMode(CullFaceMode mode) {
|
||||
m_renderState.SetCullFaceMode(mode);
|
||||
}
|
||||
|
||||
CullFaceMode GLContext::GetCullFaceMode() const {
|
||||
return m_renderState.GetCullFaceMode();
|
||||
}
|
||||
CullFaceMode GLContext::GetCullFaceMode() const {
|
||||
return m_renderState.GetCullFaceMode();
|
||||
}
|
||||
|
||||
void GLContext::SetScissorBox(IntVec4 box) {
|
||||
m_renderState.SetScissorBox(box);
|
||||
}
|
||||
void GLContext::SetScissorBox(IntVec4 box) {
|
||||
m_renderState.SetScissorBox(box);
|
||||
}
|
||||
|
||||
const IntVec4& GLContext::GetScissorBox() const {
|
||||
return m_renderState.GetScissorBox();
|
||||
}
|
||||
const IntVec4& GLContext::GetScissorBox() const {
|
||||
return m_renderState.GetScissorBox();
|
||||
}
|
||||
|
||||
// Framebuffer
|
||||
Vector<Uint> GLContext::GenFramebufferNames(Uint number) {
|
||||
return m_framebufferState.GenerateNames(number);
|
||||
}
|
||||
// Framebuffer
|
||||
void GLContext::GenFramebufferNames(Uint number, Vector<Uint>& framebuffers) {
|
||||
m_framebufferState.GenerateNames(number, framebuffers);
|
||||
}
|
||||
|
||||
SharedPtr<FramebufferObject> GLContext::GetFramebufferObject(Uint index) {
|
||||
return m_framebufferState.GetFramebufferObject(index);
|
||||
}
|
||||
const SharedPtr<FramebufferObject>& GLContext::GetFramebufferObject(Uint index) {
|
||||
return m_framebufferState.GetFramebufferObject(index);
|
||||
}
|
||||
|
||||
BindingSlot<FramebufferObject>& GLContext::GetFramebufferBindingSlot(FramebufferTarget target) {
|
||||
return m_framebufferState.GetBindingSlot(target);
|
||||
}
|
||||
BindingSlot<FramebufferObject>& GLContext::GetFramebufferBindingSlot(FramebufferTarget target) {
|
||||
return m_framebufferState.GetBindingSlot(target);
|
||||
}
|
||||
|
||||
SharedPtr<FramebufferObject> GLContext::CreateFramebufferObject(Uint index) {
|
||||
return m_framebufferState.CreateFramebufferObject(index);
|
||||
}
|
||||
const SharedPtr<FramebufferObject>& GLContext::CreateFramebufferObject(Uint index) {
|
||||
return m_framebufferState.CreateFramebufferObject(index);
|
||||
}
|
||||
|
||||
void GLContext::MarkFramebufferObjectForDeletion(Uint index) {
|
||||
m_framebufferState.MarkFramebufferObjectForDeletion(index);
|
||||
}
|
||||
void GLContext::MarkFramebufferObjectForDeletion(Uint index) {
|
||||
m_framebufferState.MarkFramebufferObjectForDeletion(index);
|
||||
}
|
||||
|
||||
Bool GLContext::ValidateFramebufferName(Uint index) const {
|
||||
return m_framebufferState.ValidateName(index);
|
||||
}
|
||||
Bool GLContext::ValidateFramebufferName(Uint index) const {
|
||||
return m_framebufferState.ValidateName(index);
|
||||
}
|
||||
|
||||
Bool GLContext::ValidateFramebufferObject(Uint index) const {
|
||||
return m_framebufferState.ValidateFramebufferObject(index);
|
||||
}
|
||||
Bool GLContext::ValidateFramebufferObject(Uint index) const {
|
||||
return m_framebufferState.ValidateFramebufferObject(index);
|
||||
}
|
||||
|
||||
// Sampler
|
||||
Vector<Uint> GLContext::GenSamplerNames(Uint number) {
|
||||
return m_samplerState.GenerateNames(number);
|
||||
}
|
||||
// Sampler
|
||||
void GLContext::GenSamplerNames(Uint number, Vector<Uint>& samplers) {
|
||||
m_samplerState.GenerateNames(number, samplers);
|
||||
}
|
||||
|
||||
SharedPtr<SamplerObject> GLContext::GetSamplerObject(Uint index) {
|
||||
return m_samplerState.GetSamplerObject(index);
|
||||
}
|
||||
const SharedPtr<SamplerObject>& GLContext::GetSamplerObject(Uint index) {
|
||||
return m_samplerState.GetSamplerObject(index);
|
||||
}
|
||||
|
||||
SharedPtr<SamplerObject> GLContext::CreateSamplerObject(Uint index) {
|
||||
return m_samplerState.CreateSamplerObject(index);
|
||||
}
|
||||
const SharedPtr<SamplerObject>& GLContext::CreateSamplerObject(Uint index) {
|
||||
return m_samplerState.CreateSamplerObject(index);
|
||||
}
|
||||
|
||||
void GLContext::MarkSamplerObjectForDeletion(Uint index) {
|
||||
// Unbind the sampler from all texture units
|
||||
if (ValidateSamplerObject(index)) {
|
||||
auto sampler = m_samplerState.GetSamplerObject(index);
|
||||
for (Int unit = 0; unit < TextureState::MAX_TEXTURE_IMAGE_UNITS; ++unit) {
|
||||
auto& textureUnit = m_textureState.GetUnitObject(unit);
|
||||
if (textureUnit.GetSamplerObject() == sampler) {
|
||||
textureUnit.SetSamplerObject(nullptr);
|
||||
}
|
||||
void GLContext::MarkSamplerObjectForDeletion(Uint index) {
|
||||
// Unbind the sampler from all texture units
|
||||
if (ValidateSamplerObject(index)) {
|
||||
auto sampler = m_samplerState.GetSamplerObject(index);
|
||||
for (Int unit = 0; unit < TextureState::MAX_TEXTURE_IMAGE_UNITS; ++unit) {
|
||||
auto& textureUnit = m_textureState.GetUnitObject(unit);
|
||||
if (textureUnit.GetSamplerObject() == sampler) {
|
||||
textureUnit.SetSamplerObject(nullptr);
|
||||
}
|
||||
}
|
||||
m_samplerState.MarkSamplerObjectForDeletion(index);
|
||||
}
|
||||
m_samplerState.MarkSamplerObjectForDeletion(index);
|
||||
}
|
||||
|
||||
Bool GLContext::ValidateSamplerName(Uint index) const {
|
||||
return m_samplerState.ValidateName(index);
|
||||
}
|
||||
Bool GLContext::ValidateSamplerName(Uint index) const {
|
||||
return m_samplerState.ValidateName(index);
|
||||
}
|
||||
|
||||
Bool GLContext::ValidateSamplerObject(Uint index) const {
|
||||
return m_samplerState.ValidateSamplerObject(index);
|
||||
}
|
||||
Bool GLContext::ValidateSamplerObject(Uint index) const {
|
||||
return m_samplerState.ValidateSamplerObject(index);
|
||||
}
|
||||
|
||||
// Renderbuffer
|
||||
Vector<Uint> GLContext::GenRenderbufferNames(Uint number) {
|
||||
return m_renderbufferState.GenerateNames(number);
|
||||
}
|
||||
// Renderbuffer
|
||||
void GLContext::GenRenderbufferNames(Uint number, Vector<Uint>& renderbuffers) {
|
||||
m_renderbufferState.GenerateNames(number, renderbuffers);
|
||||
}
|
||||
|
||||
SharedPtr<RenderbufferObject> GLContext::GetRenderbufferObject(Uint index) {
|
||||
return m_renderbufferState.GetRenderbufferObject(index);
|
||||
}
|
||||
const SharedPtr<RenderbufferObject>& GLContext::GetRenderbufferObject(Uint index) {
|
||||
return m_renderbufferState.GetRenderbufferObject(index);
|
||||
}
|
||||
|
||||
BindingSlot<RenderbufferObject>& GLContext::GetRenderbufferBindingSlot(RenderbufferTarget target) {
|
||||
return m_renderbufferState.GetBindingSlot(target);
|
||||
}
|
||||
BindingSlot<RenderbufferObject>& GLContext::GetRenderbufferBindingSlot(RenderbufferTarget target) {
|
||||
return m_renderbufferState.GetBindingSlot(target);
|
||||
}
|
||||
|
||||
SharedPtr<RenderbufferObject> GLContext::CreateRenderbufferObject(Uint index) {
|
||||
return m_renderbufferState.CreateRenderbufferObject(index);
|
||||
}
|
||||
const SharedPtr<RenderbufferObject>& GLContext::CreateRenderbufferObject(Uint index) {
|
||||
return m_renderbufferState.CreateRenderbufferObject(index);
|
||||
}
|
||||
|
||||
void GLContext::MarkRenderbufferObjectForDeletion(Uint index) {
|
||||
m_renderbufferState.MarkRenderbufferObjectForDeletion(index);
|
||||
}
|
||||
void GLContext::MarkRenderbufferObjectForDeletion(Uint index) {
|
||||
m_renderbufferState.MarkRenderbufferObjectForDeletion(index);
|
||||
}
|
||||
|
||||
Bool GLContext::ValidateRenderbufferName(Uint index) const {
|
||||
return m_renderbufferState.ValidateName(index);
|
||||
}
|
||||
} // namespace GLState
|
||||
Bool GLContext::ValidateRenderbufferName(Uint index) const {
|
||||
return m_renderbufferState.ValidateName(index);
|
||||
}
|
||||
|
||||
GLState::GLContext* pGLContext;
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
Bool GLContext::ValidateRenderbufferObject(Uint index) const {
|
||||
return m_renderbufferState.ValidateRenderbufferObject(index);
|
||||
}
|
||||
} // namespace GLState
|
||||
|
||||
UniquePtr<GLState::GLContext> pGLContext;
|
||||
} // namespace MobileGL::MG_State
|
||||
|
||||
@@ -30,42 +30,42 @@ namespace MobileGL {
|
||||
GLContext() = default;
|
||||
|
||||
// Error
|
||||
void RecordError(ErrorCode code, SharedPtr<ErrorInfo> info = nullptr);
|
||||
void RecordError(ErrorCode code, UniquePtr<ErrorInfo> info);
|
||||
Bool HasGLError() const;
|
||||
Optional<const Error> PeekGLError() const;
|
||||
Optional<Error> PopGLError();
|
||||
Optional<const Error*> PeekNonGLError() const;
|
||||
Optional<UniquePtr<Error>> PopNonGLError();
|
||||
Bool HasNonGLError() const;
|
||||
Optional<const Error> PeekNonGLError() const;
|
||||
Optional<Error> PopNonGLError();
|
||||
Optional<const Error*> PeekGLError() const;
|
||||
Optional<UniquePtr<Error>> PopGLError();
|
||||
void ClearErrors();
|
||||
|
||||
// Buffer
|
||||
Vector<Uint> GenBufferNames(Uint number);
|
||||
SharedPtr<BufferObject> GetBufferObject(Uint index);
|
||||
void GenBufferNames(Uint number, Vector<Uint>& buffers);
|
||||
const SharedPtr<BufferObject>& GetBufferObject(Uint index);
|
||||
BindingSlot<BufferObject>& GetBufferBindingSlot(BufferTarget target);
|
||||
BindingSlotRange1D<BufferObject>& GetBufferBindingPoint(BufferTarget target, Uint index);
|
||||
constexpr SizeT GetBufferBindingPointCount(BufferTarget target) const {
|
||||
return m_bufferState.GetBindingPointCount(target);
|
||||
}
|
||||
SharedPtr<BufferObject> CreateBufferObject(Uint index);
|
||||
const SharedPtr<BufferObject>& CreateBufferObject(Uint index);
|
||||
void MarkBufferObjectForDeletion(Uint index);
|
||||
Bool ValidateBufferName(Uint index) const;
|
||||
Bool ValidateBufferObject(Uint index) const;
|
||||
|
||||
// VertexArray
|
||||
Vector<Uint> GenVertexArrayNames(Uint number);
|
||||
SharedPtr<VertexArrayObject> GetVertexArrayObject(Uint index);
|
||||
void GenVertexArrayNames(Uint number, Vector<Uint>& vertexArrays);
|
||||
const SharedPtr<VertexArrayObject>& GetVertexArrayObject(Uint index);
|
||||
void BindVertexArray(Uint index);
|
||||
SharedPtr<VertexArrayObject> CreateVertexArrayObject(Uint index);
|
||||
const SharedPtr<VertexArrayObject>& CreateVertexArrayObject(Uint index);
|
||||
void MarkVertexArrayForDeletion(Uint index);
|
||||
Bool ValidateVertexArrayName(Uint index) const;
|
||||
Bool ValidateVertexArrayObject(Uint index) const;
|
||||
SharedPtr<VertexArrayObject> GetBoundVertexArray();
|
||||
const SharedPtr<VertexArrayObject>& GetBoundVertexArray();
|
||||
|
||||
// Texture
|
||||
Vector<Uint> GenTextureNames(Uint number);
|
||||
SharedPtr<ITextureObject> GetTextureObject(Uint index);
|
||||
SharedPtr<ITextureObject> CreateTextureObject(Uint index, TextureTarget target);
|
||||
void GenTextureNames(Uint number, Vector<Uint>& textures);
|
||||
const SharedPtr<ITextureObject>& GetTextureObject(Uint index);
|
||||
const SharedPtr<ITextureObject>& CreateTextureObject(Uint index, TextureTarget target);
|
||||
void MarkTextureObjectForDeletion(Uint index);
|
||||
TextureUnit& GetTextureUnitObject(Int unit);
|
||||
Bool ValidateTextureName(Uint index) const;
|
||||
@@ -80,10 +80,10 @@ namespace MobileGL {
|
||||
void MarkShaderForDeletion(Uint index);
|
||||
Bool ValidateProgramName(Uint index) const;
|
||||
Bool ValidateShaderName(Uint index) const;
|
||||
SharedPtr<ProgramObject> GetProgramObject(Uint index);
|
||||
SharedPtr<ShaderObject> GetShaderObject(Uint index);
|
||||
const SharedPtr<ProgramObject>& GetProgramObject(Uint index);
|
||||
const SharedPtr<ShaderObject>& GetShaderObject(Uint index);
|
||||
void UseProgram(Uint program);
|
||||
SharedPtr<ProgramObject> GetCurrentProgram();
|
||||
const SharedPtr<ProgramObject>& GetCurrentProgram();
|
||||
|
||||
// RenderState
|
||||
Uint GetRenderStateParametersVersion() const;
|
||||
@@ -106,13 +106,13 @@ namespace MobileGL {
|
||||
void SetDepthMask(Bool flag);
|
||||
Bool GetDepthMask() const;
|
||||
void SetColorMask(BoolVec4 mask);
|
||||
const BoolVec4 GetColorMask() const;
|
||||
BoolVec4 GetColorMask() const;
|
||||
void SetClearColor(FloatVec4 color);
|
||||
const FloatVec4& GetClearColor() const;
|
||||
void SetClearDepth(Float depth);
|
||||
Float GetClearDepth() const;
|
||||
void SetClearStencil(Int stencil);
|
||||
Int GetClearStencil() const;
|
||||
Uint32 GetClearStencil() const;
|
||||
void SetPixelStoreParam(PixelStoreParam param, Int value);
|
||||
Int GetPixelStoreParam(PixelStoreParam param) const;
|
||||
PixelStoreParameters GetPixelStoreParameters(Bool isUnpack) const;
|
||||
@@ -122,27 +122,27 @@ namespace MobileGL {
|
||||
const IntVec4& GetScissorBox() const; // x, y, width, height
|
||||
|
||||
// Framebuffer
|
||||
Vector<Uint> GenFramebufferNames(Uint number);
|
||||
SharedPtr<FramebufferObject> GetFramebufferObject(Uint index);
|
||||
void GenFramebufferNames(Uint number, Vector<Uint>& framebuffers);
|
||||
const SharedPtr<FramebufferObject>& GetFramebufferObject(Uint index);
|
||||
BindingSlot<FramebufferObject>& GetFramebufferBindingSlot(FramebufferTarget target);
|
||||
SharedPtr<FramebufferObject> CreateFramebufferObject(Uint index);
|
||||
const SharedPtr<FramebufferObject>& CreateFramebufferObject(Uint index);
|
||||
void MarkFramebufferObjectForDeletion(Uint index);
|
||||
Bool ValidateFramebufferName(Uint index) const;
|
||||
Bool ValidateFramebufferObject(Uint index) const;
|
||||
|
||||
// Sampler
|
||||
Vector<Uint> GenSamplerNames(Uint number);
|
||||
SharedPtr<SamplerObject> GetSamplerObject(Uint index);
|
||||
SharedPtr<SamplerObject> CreateSamplerObject(Uint index);
|
||||
void GenSamplerNames(Uint number, Vector<Uint>& samplers);
|
||||
const SharedPtr<SamplerObject>& GetSamplerObject(Uint index);
|
||||
const SharedPtr<SamplerObject>& CreateSamplerObject(Uint index);
|
||||
void MarkSamplerObjectForDeletion(Uint index);
|
||||
Bool ValidateSamplerName(Uint index) const;
|
||||
Bool ValidateSamplerObject(Uint index) const;
|
||||
|
||||
// Renderbuffer
|
||||
Vector<Uint> GenRenderbufferNames(Uint number);
|
||||
SharedPtr<RenderbufferObject> GetRenderbufferObject(Uint index);
|
||||
void GenRenderbufferNames(Uint number, Vector<Uint>& renderbuffers);
|
||||
const SharedPtr<RenderbufferObject>& GetRenderbufferObject(Uint index);
|
||||
BindingSlot<RenderbufferObject>& GetRenderbufferBindingSlot(RenderbufferTarget target);
|
||||
SharedPtr<RenderbufferObject> CreateRenderbufferObject(Uint index);
|
||||
const SharedPtr<RenderbufferObject>& CreateRenderbufferObject(Uint index);
|
||||
void MarkRenderbufferObjectForDeletion(Uint index);
|
||||
Bool ValidateRenderbufferName(Uint index) const;
|
||||
Bool ValidateRenderbufferObject(Uint index) const;
|
||||
@@ -161,6 +161,6 @@ namespace MobileGL {
|
||||
};
|
||||
} // namespace GLState
|
||||
|
||||
extern GLState::GLContext* pGLContext;
|
||||
extern UniquePtr<GLState::GLContext> pGLContext;
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
|
||||
@@ -10,57 +10,53 @@
|
||||
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToGL/ErrorCodeConverter.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
void ErrorState::RecordError(ErrorCode code, SharedPtr<ErrorInfo> info) {
|
||||
if (code == ErrorCode::NoError) {
|
||||
MGLOG_E("Recording Non-OpenGL error:\n%s", info->ToString().c_str());
|
||||
m_nonGLErrors.push_back(Error{code, info});
|
||||
} else {
|
||||
MGLOG_E("Recording OpenGL error (%s):\n%s",
|
||||
MG_Util::ConvertGLEnumToString(MG_Util::ConvertErrorCodeToGLEnum(code)).c_str(),
|
||||
info->ToString().c_str());
|
||||
m_errors.push_back(Error{code, info});
|
||||
}
|
||||
}
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
void ErrorState::RecordError(ErrorCode code, UniquePtr<ErrorInfo> info) {
|
||||
if (code == ErrorCode::NoError) {
|
||||
MGLOG_E("Recording Non-OpenGL error:\n%s", info->toString().c_str());
|
||||
m_nonGLErrors.push_back(MakeUnique<Error>(code, Move(info)));
|
||||
} else {
|
||||
MGLOG_E("Recording OpenGL error (%s):\n%s",
|
||||
MG_Util::ConvertGLEnumToString(MG_Util::ConvertErrorCodeToGLEnum(code)).c_str(),
|
||||
info->toString().c_str());
|
||||
m_errors.push_back(MakeUnique<Error>(code, Move(info)));
|
||||
}
|
||||
}
|
||||
|
||||
Bool ErrorState::HasNonGLError() const {
|
||||
return !m_nonGLErrors.empty();
|
||||
}
|
||||
Bool ErrorState::HasNonGLError() const {
|
||||
return !m_nonGLErrors.empty();
|
||||
}
|
||||
|
||||
Optional<const Error> ErrorState::PeekNonGLError() const {
|
||||
if (m_nonGLErrors.empty()) return Optional<const Error>{};
|
||||
return Optional<const Error>{m_nonGLErrors.front()};
|
||||
}
|
||||
Optional<const Error*> ErrorState::PeekNonGLError() const {
|
||||
if (m_nonGLErrors.empty()) return Nullopt;
|
||||
return Optional<const Error*>{m_nonGLErrors.front().get()};
|
||||
}
|
||||
|
||||
Optional<Error> ErrorState::PopNonGLError() {
|
||||
if (m_nonGLErrors.empty()) return Optional<const Error>{};
|
||||
auto error = Move(m_nonGLErrors.front());
|
||||
m_nonGLErrors.erase(m_nonGLErrors.begin());
|
||||
return Optional<const Error>{error};
|
||||
}
|
||||
Optional<UniquePtr<Error>> ErrorState::PopNonGLError() {
|
||||
if (m_nonGLErrors.empty()) return Nullopt;
|
||||
auto error = Move(m_nonGLErrors.front());
|
||||
m_nonGLErrors.erase(m_nonGLErrors.begin());
|
||||
return Move(error);
|
||||
}
|
||||
|
||||
Bool ErrorState::HasGLError() const {
|
||||
return !m_errors.empty();
|
||||
}
|
||||
Bool ErrorState::HasGLError() const {
|
||||
return !m_errors.empty();
|
||||
}
|
||||
|
||||
Optional<const Error> ErrorState::PeekGLError() const {
|
||||
if (m_errors.empty()) return Optional<const Error>{};
|
||||
return Optional<const Error>{m_errors.front()};
|
||||
}
|
||||
Optional<const Error*> ErrorState::PeekGLError() const {
|
||||
if (m_errors.empty()) return Optional<const Error*>{};
|
||||
return Optional<const Error*>{m_errors.front().get()};
|
||||
}
|
||||
|
||||
Optional<Error> ErrorState::PopGLError() {
|
||||
if (m_errors.empty()) return Optional<const Error>{};
|
||||
auto error = Move(m_errors.front());
|
||||
m_errors.erase(m_errors.begin());
|
||||
return Optional<const Error>{error};
|
||||
}
|
||||
Optional<UniquePtr<Error>> ErrorState::PopGLError() {
|
||||
if (m_errors.empty()) return Nullopt;
|
||||
auto error = Move(m_errors.front());
|
||||
m_errors.erase(m_errors.begin());
|
||||
return Move(error);
|
||||
}
|
||||
|
||||
void ErrorState::Clear() {
|
||||
m_errors.clear();
|
||||
m_nonGLErrors.clear();
|
||||
}
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
void ErrorState::Clear() {
|
||||
m_errors.clear();
|
||||
m_nonGLErrors.clear();
|
||||
}
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -14,26 +14,24 @@
|
||||
namespace MobileGL {
|
||||
struct Error {
|
||||
ErrorCode code;
|
||||
SharedPtr<ErrorInfo> info;
|
||||
UniquePtr<ErrorInfo> info;
|
||||
};
|
||||
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
class ErrorState {
|
||||
public:
|
||||
void RecordError(ErrorCode code, SharedPtr<ErrorInfo> info = nullptr);
|
||||
Bool HasNonGLError() const;
|
||||
Optional<const Error> PeekNonGLError() const;
|
||||
Optional<Error> PopNonGLError();
|
||||
Bool HasGLError() const;
|
||||
Optional<const Error> PeekGLError() const;
|
||||
Optional<Error> PopGLError();
|
||||
void Clear();
|
||||
namespace MG_State::GLState {
|
||||
class ErrorState {
|
||||
public:
|
||||
void RecordError(ErrorCode code, UniquePtr<ErrorInfo> info);
|
||||
Bool HasNonGLError() const;
|
||||
Optional<const Error*> PeekNonGLError() const;
|
||||
Optional<UniquePtr<Error>> PopNonGLError();
|
||||
Bool HasGLError() const;
|
||||
Optional<const Error*> PeekGLError() const;
|
||||
Optional<UniquePtr<Error>> PopGLError();
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
Vector<Error> m_errors;
|
||||
Vector<Error> m_nonGLErrors;
|
||||
};
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
private:
|
||||
Vector<UniquePtr<Error>> m_errors;
|
||||
Vector<UniquePtr<Error>> m_nonGLErrors;
|
||||
};
|
||||
} // namespace MG_State::GLState
|
||||
} // namespace MobileGL
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace MobileGL {
|
||||
class ErrorInfo {
|
||||
public:
|
||||
virtual ~ErrorInfo() = default;
|
||||
virtual String ToString() const = 0;
|
||||
virtual String toString() const = 0;
|
||||
};
|
||||
|
||||
class GenericErrorInfo : public ErrorInfo {
|
||||
@@ -24,7 +24,7 @@ namespace MobileGL {
|
||||
explicit GenericErrorInfo(String m_prefix, String m_prefix_2, String message)
|
||||
: m_message(Move(message)), m_prefix(Move(m_prefix)), m_prefix_2(Move(m_prefix_2)) {}
|
||||
|
||||
String ToString() const override {
|
||||
String toString() const override {
|
||||
StringStream ss;
|
||||
if (m_prefix.has_value()) {
|
||||
ss << "[" << m_prefix.value() << "] ";
|
||||
|
||||
@@ -9,157 +9,153 @@
|
||||
#include "FramebufferObject.h"
|
||||
#include "MG_Util/Types.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
// FramebufferAttachmentObject
|
||||
FramebufferAttachmentObject::FramebufferAttachmentObject(
|
||||
SharedPtr<MG_State::GLState::ITextureObject> texture, Int level)
|
||||
: m_texture(texture), m_textureLevel(level) {}
|
||||
FramebufferAttachmentObject::FramebufferAttachmentObject(SharedPtr<RenderbufferObject> renderbuffer)
|
||||
: m_renderbuffer(renderbuffer) {}
|
||||
FramebufferAttachmentObject::FramebufferAttachmentObject(Bool IsValid)
|
||||
: m_texture(nullptr), m_renderbuffer(nullptr) {
|
||||
m_isValid = IsValid;
|
||||
}
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
// FramebufferAttachmentObject
|
||||
FramebufferAttachmentObject::FramebufferAttachmentObject(
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& texture, Int level)
|
||||
: m_texture(texture), m_textureLevel(level) {}
|
||||
FramebufferAttachmentObject::FramebufferAttachmentObject(const SharedPtr<RenderbufferObject>& renderbuffer)
|
||||
: m_renderbuffer(renderbuffer) {}
|
||||
FramebufferAttachmentObject::FramebufferAttachmentObject(Bool IsValid)
|
||||
: m_texture(nullptr), m_renderbuffer(nullptr) {
|
||||
m_isValid = IsValid;
|
||||
}
|
||||
|
||||
Bool FramebufferAttachmentObject::IsTexture() const {
|
||||
return m_texture != nullptr;
|
||||
}
|
||||
Bool FramebufferAttachmentObject::IsTexture() const {
|
||||
return m_texture != nullptr;
|
||||
}
|
||||
|
||||
Bool FramebufferAttachmentObject::IsRenderbuffer() const {
|
||||
return m_renderbuffer != nullptr;
|
||||
}
|
||||
Bool FramebufferAttachmentObject::IsRenderbuffer() const {
|
||||
return m_renderbuffer != nullptr;
|
||||
}
|
||||
|
||||
Bool FramebufferAttachmentObject::IsEmpty() const {
|
||||
return m_texture == nullptr && m_renderbuffer == nullptr;
|
||||
}
|
||||
Bool FramebufferAttachmentObject::IsEmpty() const {
|
||||
return m_texture == nullptr && m_renderbuffer == nullptr;
|
||||
}
|
||||
|
||||
SharedPtr<MG_State::GLState::ITextureObject> FramebufferAttachmentObject::GetTexture() const {
|
||||
return m_texture;
|
||||
}
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& FramebufferAttachmentObject::GetTexture() const {
|
||||
return m_texture;
|
||||
}
|
||||
|
||||
SharedPtr<RenderbufferObject> FramebufferAttachmentObject::GetRenderbuffer() const {
|
||||
return m_renderbuffer;
|
||||
}
|
||||
const SharedPtr<RenderbufferObject>& FramebufferAttachmentObject::GetRenderbuffer() const {
|
||||
return m_renderbuffer;
|
||||
}
|
||||
|
||||
Int FramebufferAttachmentObject::GetTextureLevel() const {
|
||||
return m_textureLevel;
|
||||
}
|
||||
Int FramebufferAttachmentObject::GetTextureLevel() const {
|
||||
return m_textureLevel;
|
||||
}
|
||||
|
||||
Bool FramebufferAttachmentObject::IsComplete() const {
|
||||
if (IsTexture()) {
|
||||
Bool complete = m_texture->IsComplete();
|
||||
return complete;
|
||||
} else if (IsRenderbuffer()) {
|
||||
Bool complete = m_renderbuffer->IsAllocated();
|
||||
return complete;
|
||||
}
|
||||
Bool FramebufferAttachmentObject::IsComplete() const {
|
||||
if (IsTexture()) {
|
||||
Bool complete = m_texture->IsComplete();
|
||||
return complete;
|
||||
} else if (IsRenderbuffer()) {
|
||||
Bool complete = m_renderbuffer->IsAllocated();
|
||||
return complete;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IntVec3 FramebufferAttachmentObject::GetSize() const {
|
||||
if (IsTexture()) {
|
||||
// TODO: get correct upload target
|
||||
MOBILEGL_ASSERT(nullptr != static_cast<MG_State::GLState::TextureObjectMipmap*>(m_texture.get()),
|
||||
"Texture object here should always be an object with mipmap");
|
||||
auto textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(m_texture.get());
|
||||
return textureMipmapObject->GetMipmapTexelSize(TextureUploadTarget::Texture2D, m_textureLevel);
|
||||
} else if (IsRenderbuffer()) {
|
||||
return {m_renderbuffer->GetWidth(), m_renderbuffer->GetHeight(), 1};
|
||||
}
|
||||
return {0, 0, 0};
|
||||
}
|
||||
|
||||
Bool FramebufferAttachmentObject::IsValid() const {
|
||||
return m_isValid;
|
||||
}
|
||||
|
||||
// FramebufferObject
|
||||
FramebufferObject::FramebufferObject(Uint externalIndex)
|
||||
: m_externalIndex(externalIndex), m_attachmentVersions{}, m_drawBuffers{} {
|
||||
m_attachmentObjects.fill(FramebufferAttachmentObject(false));
|
||||
m_drawBuffers.fill(FramebufferAttachmentType::None);
|
||||
m_drawBuffers[0] = FramebufferAttachmentType::Color0;
|
||||
m_attachmentVersions.fill(0);
|
||||
}
|
||||
|
||||
void FramebufferObject::AttachTexture(FramebufferAttachmentType type, const SharedPtr<ITextureObject>& texture,
|
||||
int level) {
|
||||
m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(texture, level);
|
||||
BumpAttachmentVersion(type);
|
||||
}
|
||||
|
||||
void FramebufferObject::AttachRenderbuffer(FramebufferAttachmentType type,
|
||||
const SharedPtr<RenderbufferObject>& renderbuffer) {
|
||||
m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(renderbuffer);
|
||||
BumpAttachmentVersion(type);
|
||||
}
|
||||
|
||||
void FramebufferObject::Detach(FramebufferAttachmentType type) {
|
||||
m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(false);
|
||||
BumpAttachmentVersion(type);
|
||||
}
|
||||
|
||||
const FramebufferAttachmentObject& FramebufferObject::GetAttachment(FramebufferAttachmentType type) const {
|
||||
return m_attachmentObjects[static_cast<SizeT>(type)];
|
||||
}
|
||||
|
||||
const FramebufferObject::FramebufferAttachmentObjectArray& FramebufferObject::GetAllAttachmentObjects() const {
|
||||
return m_attachmentObjects;
|
||||
}
|
||||
|
||||
Bool FramebufferObject::CheckCompleteness() const {
|
||||
if (m_attachmentObjects.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Int width = -1, height = -1;
|
||||
Int validAttachmentCount = 0;
|
||||
for (const auto& attachmentObject : m_attachmentObjects) {
|
||||
if (!attachmentObject.IsValid()) continue;
|
||||
|
||||
++validAttachmentCount;
|
||||
const auto& attachment = attachmentObject;
|
||||
auto attachmentSize = attachment.GetSize();
|
||||
Int w = attachmentSize.x();
|
||||
Int h = attachmentSize.y();
|
||||
|
||||
if (width == -1) {
|
||||
width = w;
|
||||
height = h;
|
||||
} else if (width != w || height != h) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IntVec3 FramebufferAttachmentObject::GetSize() const {
|
||||
if (IsTexture()) {
|
||||
// TODO: get correct upload target
|
||||
MOBILEGL_ASSERT(nullptr != dynamic_cast<MG_State::GLState::TextureObjectMipmap*>(m_texture.get()),
|
||||
"Texture object here should always be an object with mipmap");
|
||||
auto textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(m_texture.get());
|
||||
return textureMipmapObject->GetMipmapTexelSize(TextureUploadTarget::Texture2D, m_textureLevel);
|
||||
} else if (IsRenderbuffer()) {
|
||||
return IntVec3(m_renderbuffer->GetWidth(), m_renderbuffer->GetHeight(), 1);
|
||||
}
|
||||
return {0, 0, 0};
|
||||
if (!attachment.IsComplete()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Bool FramebufferAttachmentObject::IsValid() const {
|
||||
return m_isValid;
|
||||
}
|
||||
if (validAttachmentCount == 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// FramebufferObject
|
||||
FramebufferObject::FramebufferObject(Uint externalIndex) : m_externalIndex(externalIndex) {
|
||||
m_attachmentObjects.fill(FramebufferAttachmentObject(false));
|
||||
m_drawBuffers.fill(FramebufferAttachmentType::None);
|
||||
m_drawBuffers[0] = FramebufferAttachmentType::Color0;
|
||||
m_attachmentVersions.fill(0);
|
||||
}
|
||||
void FramebufferObject::SetDrawBuffer(Uint index, FramebufferAttachmentType buffer) {
|
||||
if (m_drawBuffers[index] == buffer) return;
|
||||
m_drawBuffers[index] = buffer;
|
||||
BumpAttachmentVersion(buffer);
|
||||
}
|
||||
|
||||
void FramebufferObject::AttachTexture(FramebufferAttachmentType type, SharedPtr<ITextureObject> texture,
|
||||
int level) {
|
||||
m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(std::move(texture), level);
|
||||
BumpAttachmentVersion(type);
|
||||
}
|
||||
const FramebufferObject::FramebufferAttachmentArray& FramebufferObject::GetDrawBuffers() const {
|
||||
return m_drawBuffers;
|
||||
}
|
||||
|
||||
void FramebufferObject::AttachRenderbuffer(FramebufferAttachmentType type,
|
||||
std::shared_ptr<RenderbufferObject> renderbuffer) {
|
||||
m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(renderbuffer);
|
||||
BumpAttachmentVersion(type);
|
||||
}
|
||||
Uint FramebufferObject::GetExternalIndex() const {
|
||||
return m_externalIndex;
|
||||
}
|
||||
|
||||
void FramebufferObject::Detach(FramebufferAttachmentType type) {
|
||||
m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(false);
|
||||
BumpAttachmentVersion(type);
|
||||
}
|
||||
|
||||
const FramebufferAttachmentObject& FramebufferObject::GetAttachment(FramebufferAttachmentType type) const {
|
||||
return m_attachmentObjects[static_cast<SizeT>(type)];
|
||||
}
|
||||
|
||||
const FramebufferObject::FramebufferAttachmentObjectArray& FramebufferObject::GetAllAttachmentObjects()
|
||||
const {
|
||||
return m_attachmentObjects;
|
||||
}
|
||||
|
||||
Bool FramebufferObject::CheckCompleteness() const {
|
||||
if (m_attachmentObjects.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Int width = -1, height = -1;
|
||||
Int validAttachmentCount = 0;
|
||||
for (SizeT i = 0; i < m_attachmentObjects.size(); ++i) {
|
||||
if (!m_attachmentObjects[i].IsValid()) continue;
|
||||
|
||||
++validAttachmentCount;
|
||||
const auto& attachment = m_attachmentObjects[i];
|
||||
auto attachmentSize = attachment.GetSize();
|
||||
Int w = attachmentSize.x();
|
||||
Int h = attachmentSize.y();
|
||||
|
||||
if (width == -1) {
|
||||
width = w;
|
||||
height = h;
|
||||
} else if (width != w || height != h) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!attachment.IsComplete()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (validAttachmentCount == 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void FramebufferObject::SetDrawBuffer(Uint index, FramebufferAttachmentType buffer) {
|
||||
if (m_drawBuffers[index] == buffer) return;
|
||||
m_drawBuffers[index] = buffer;
|
||||
BumpAttachmentVersion(buffer);
|
||||
}
|
||||
|
||||
const FramebufferObject::FramebufferAttachmentArray& FramebufferObject::GetDrawBuffers() const {
|
||||
return m_drawBuffers;
|
||||
}
|
||||
|
||||
Uint FramebufferObject::GetExternalIndex() const {
|
||||
return m_externalIndex;
|
||||
}
|
||||
|
||||
void FramebufferObject::BumpAttachmentVersion(FramebufferAttachmentType type) {
|
||||
++m_attachmentVersions[static_cast<SizeT>(type)];
|
||||
++m_objectVersion;
|
||||
}
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
void FramebufferObject::BumpAttachmentVersion(FramebufferAttachmentType type) {
|
||||
++m_attachmentVersions[static_cast<SizeT>(type)];
|
||||
++m_objectVersion;
|
||||
}
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
#include "MG_Util/Types.h"
|
||||
#include <Includes.h>
|
||||
#include <MG_State/GLState/TextureState/TextureObject.h>
|
||||
#include <MG_State/GLState/RenderbufferState/RenderbufferObject.h>
|
||||
@@ -62,86 +63,84 @@ namespace MobileGL {
|
||||
Color29,
|
||||
Color30,
|
||||
Color31,
|
||||
ColorMax = Color31,
|
||||
|
||||
FramebufferAttachmentTypeCount,
|
||||
Unknown = -1
|
||||
};
|
||||
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
class FramebufferAttachmentObject {
|
||||
public:
|
||||
explicit FramebufferAttachmentObject(SharedPtr<MG_State::GLState::ITextureObject> texture,
|
||||
Int level = 0);
|
||||
explicit FramebufferAttachmentObject(SharedPtr<RenderbufferObject> renderbuffer);
|
||||
explicit FramebufferAttachmentObject(Bool IsValid = true);
|
||||
namespace MG_State::GLState {
|
||||
class FramebufferAttachmentObject {
|
||||
public:
|
||||
explicit FramebufferAttachmentObject(const SharedPtr<MG_State::GLState::ITextureObject>& texture,
|
||||
Int level = 0);
|
||||
explicit FramebufferAttachmentObject(const SharedPtr<RenderbufferObject>& renderbuffer);
|
||||
explicit FramebufferAttachmentObject(Bool IsValid = true);
|
||||
|
||||
Bool IsTexture() const;
|
||||
Bool IsRenderbuffer() const;
|
||||
Bool IsEmpty() const;
|
||||
SharedPtr<MG_State::GLState::ITextureObject> GetTexture() const;
|
||||
SharedPtr<RenderbufferObject> GetRenderbuffer() const;
|
||||
Int GetTextureLevel() const;
|
||||
Bool IsComplete() const;
|
||||
IntVec3 GetSize() const;
|
||||
Bool IsValid() const;
|
||||
Bool IsTexture() const;
|
||||
Bool IsRenderbuffer() const;
|
||||
Bool IsEmpty() const;
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& GetTexture() const;
|
||||
const SharedPtr<RenderbufferObject>& GetRenderbuffer() const;
|
||||
Int GetTextureLevel() const;
|
||||
Bool IsComplete() const;
|
||||
IntVec3 GetSize() const;
|
||||
Bool IsValid() const;
|
||||
|
||||
private:
|
||||
SharedPtr<MG_State::GLState::ITextureObject> m_texture = nullptr;
|
||||
SharedPtr<RenderbufferObject> m_renderbuffer = nullptr;
|
||||
Int m_textureLevel = 0;
|
||||
Bool m_isValid = true;
|
||||
};
|
||||
private:
|
||||
SharedPtr<MG_State::GLState::ITextureObject> m_texture = nullptr;
|
||||
SharedPtr<RenderbufferObject> m_renderbuffer = nullptr;
|
||||
Int m_textureLevel = 0;
|
||||
Bool m_isValid = true;
|
||||
};
|
||||
|
||||
class FramebufferObject {
|
||||
public:
|
||||
static constexpr Uint MAX_DRAW_BUFFERS = 8;
|
||||
class FramebufferObject {
|
||||
public:
|
||||
static constexpr Uint MAX_DRAW_BUFFERS = 8;
|
||||
|
||||
using TargetEnum = FramebufferTarget;
|
||||
using FramebufferAttachmentObjectArray =
|
||||
Array<FramebufferAttachmentObject,
|
||||
static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>;
|
||||
using FramebufferAttachmentArray = Array<FramebufferAttachmentType, MAX_DRAW_BUFFERS>;
|
||||
using FramebufferAttachmentVersionArray =
|
||||
Array<Uint16, static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>;
|
||||
using TargetEnum = FramebufferTarget;
|
||||
using FramebufferAttachmentObjectArray =
|
||||
Array<FramebufferAttachmentObject,
|
||||
static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>;
|
||||
using FramebufferAttachmentArray = Array<FramebufferAttachmentType, MAX_DRAW_BUFFERS>;
|
||||
using FramebufferAttachmentVersionArray =
|
||||
Array<Uint16, static_cast<SizeT>(FramebufferAttachmentType::FramebufferAttachmentTypeCount)>;
|
||||
|
||||
FramebufferObject(Uint externalIndex);
|
||||
FramebufferObject(Uint externalIndex);
|
||||
|
||||
void AttachTexture(FramebufferAttachmentType type, SharedPtr<ITextureObject> texture, int level = 0);
|
||||
void AttachRenderbuffer(FramebufferAttachmentType type,
|
||||
std::shared_ptr<RenderbufferObject> renderbuffer);
|
||||
void Detach(FramebufferAttachmentType type);
|
||||
const FramebufferAttachmentObject& GetAttachment(FramebufferAttachmentType type) const;
|
||||
const FramebufferAttachmentObjectArray& GetAllAttachmentObjects() const;
|
||||
Bool CheckCompleteness() const;
|
||||
// aka. `buffer` as in glDrawBuffers/glReadBuffers
|
||||
void SetDrawBuffer(Uint index, FramebufferAttachmentType buffer);
|
||||
const FramebufferAttachmentArray& GetDrawBuffers() const;
|
||||
void SetReadBuffer(FramebufferAttachmentType buf) { m_readBuffer = buf; }
|
||||
FramebufferAttachmentType GetReadBuffer() const { return m_readBuffer; }
|
||||
void AttachTexture(FramebufferAttachmentType type, const SharedPtr<ITextureObject>& texture, int level = 0);
|
||||
void AttachRenderbuffer(FramebufferAttachmentType type, const SharedPtr<RenderbufferObject>& renderbuffer);
|
||||
void Detach(FramebufferAttachmentType type);
|
||||
const FramebufferAttachmentObject& GetAttachment(FramebufferAttachmentType type) const;
|
||||
const FramebufferAttachmentObjectArray& GetAllAttachmentObjects() const;
|
||||
Bool CheckCompleteness() const;
|
||||
// aka. `buffer` as in glDrawBuffers/glReadBuffers
|
||||
void SetDrawBuffer(Uint index, FramebufferAttachmentType buffer);
|
||||
const FramebufferAttachmentArray& GetDrawBuffers() const;
|
||||
void SetReadBuffer(FramebufferAttachmentType buf) { m_readBuffer = buf; }
|
||||
FramebufferAttachmentType GetReadBuffer() const { return m_readBuffer; }
|
||||
|
||||
const FramebufferAttachmentVersionArray GetAllFramebufferAttachmentVersions() const {
|
||||
return m_attachmentVersions;
|
||||
}
|
||||
FramebufferAttachmentVersionArray GetAllFramebufferAttachmentVersions() const {
|
||||
return m_attachmentVersions;
|
||||
}
|
||||
|
||||
Uint16 GetObjectVersion() const { return m_objectVersion; }
|
||||
Uint16 GetObjectVersion() const { return m_objectVersion; }
|
||||
|
||||
Uint GetExternalIndex() const;
|
||||
Uint GetExternalIndex() const;
|
||||
|
||||
private:
|
||||
void BumpAttachmentVersion(FramebufferAttachmentType type);
|
||||
private:
|
||||
void BumpAttachmentVersion(FramebufferAttachmentType type);
|
||||
|
||||
const Uint m_externalIndex = 0;
|
||||
FramebufferAttachmentObjectArray m_attachmentObjects;
|
||||
FramebufferAttachmentVersionArray m_attachmentVersions;
|
||||
const Uint m_externalIndex = 0;
|
||||
FramebufferAttachmentObjectArray m_attachmentObjects;
|
||||
FramebufferAttachmentVersionArray m_attachmentVersions;
|
||||
|
||||
FramebufferAttachmentArray m_drawBuffers; // Probably no versioning needed for this, just check equality
|
||||
FramebufferAttachmentType m_readBuffer = FramebufferAttachmentType::Color0; // ditto
|
||||
FramebufferAttachmentArray m_drawBuffers; // Probably no versioning needed for this, just check equality
|
||||
FramebufferAttachmentType m_readBuffer = FramebufferAttachmentType::Color0; // ditto
|
||||
|
||||
// This version will bump when draw/read buffer changes (by `glDrawBuffer(s)`/`glReadBuffer`)
|
||||
Uint16 m_objectVersion = 0;
|
||||
};
|
||||
// This version will bump when draw/read buffer changes (by `glDrawBuffer(s)`/`glReadBuffer`)
|
||||
Uint16 m_objectVersion = 0;
|
||||
};
|
||||
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MG_State::GLState
|
||||
} // namespace MobileGL
|
||||
|
||||
@@ -9,74 +9,73 @@
|
||||
#include "FramebufferState.h"
|
||||
#include "MG_State/GLState/FramebufferState/FramebufferObject.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
FramebufferState::FramebufferState() {
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
m_bindingSlots[i] = BindingSlot<FramebufferObject>(static_cast<FramebufferTarget>(i));
|
||||
}
|
||||
}
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
FramebufferState::FramebufferState() {
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
m_bindingSlots[i] = BindingSlot<FramebufferObject>(static_cast<FramebufferTarget>(i));
|
||||
}
|
||||
}
|
||||
|
||||
SharedPtr<FramebufferObject> FramebufferState::GetFramebufferObject(Uint index) {
|
||||
auto it = m_framebufferObjects.find(index);
|
||||
if (it != m_framebufferObjects.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
const SharedPtr<FramebufferObject>& FramebufferState::GetFramebufferObject(Uint index) {
|
||||
auto it = m_framebufferObjects.find(index);
|
||||
if (it != m_framebufferObjects.end()) {
|
||||
return it->second;
|
||||
}
|
||||
static SharedPtr<FramebufferObject> nullFramebufferObject = nullptr;
|
||||
return nullFramebufferObject;
|
||||
}
|
||||
|
||||
Vector<Uint> FramebufferState::GenerateNames(Uint number) {
|
||||
Vector<Uint> buffers(number);
|
||||
m_indexGenerator.Generate(number, buffers.data());
|
||||
return buffers;
|
||||
}
|
||||
void FramebufferState::GenerateNames(Uint number, Vector<Uint>& buffers) {
|
||||
buffers.resize(number);
|
||||
m_indexGenerator.Generate(number, buffers.data());
|
||||
}
|
||||
|
||||
SharedPtr<FramebufferObject> FramebufferState::CreateFramebufferObject(Uint index) {
|
||||
if (index == 0) {
|
||||
if (!m_indexGenerator.IsValid(0)) {
|
||||
m_indexGenerator.Insert(0);
|
||||
} else {
|
||||
return nullptr;
|
||||
const SharedPtr<FramebufferObject>& FramebufferState::CreateFramebufferObject(Uint index) {
|
||||
if (index == 0) {
|
||||
if (!m_indexGenerator.IsValid(0)) {
|
||||
m_indexGenerator.Insert(0);
|
||||
} else {
|
||||
static SharedPtr<FramebufferObject> nullFramebufferObject = nullptr;
|
||||
return nullFramebufferObject;
|
||||
}
|
||||
}
|
||||
auto& framebufferObject = m_framebufferObjects[index];
|
||||
if (!framebufferObject) {
|
||||
framebufferObject = MakeShared<FramebufferObject>(index);
|
||||
}
|
||||
return framebufferObject;
|
||||
}
|
||||
|
||||
BindingSlot<FramebufferObject>& FramebufferState::GetBindingSlot(FramebufferTarget target) {
|
||||
for (auto& bindingSlot : m_bindingSlots) {
|
||||
if (bindingSlot.GetTarget() == target) {
|
||||
return bindingSlot;
|
||||
}
|
||||
}
|
||||
MOBILEGL_ASSERT(false, "Invalid FramebufferTarget enum value: %d", static_cast<int>(target));
|
||||
return m_bindingSlots[0];
|
||||
}
|
||||
|
||||
void FramebufferState::MarkFramebufferObjectForDeletion(Uint index) {
|
||||
if (m_indexGenerator.IsValid(index)) {
|
||||
auto it = m_framebufferObjects.find(index);
|
||||
if (it != m_framebufferObjects.end()) {
|
||||
for (auto& bindingSlot : m_bindingSlots) {
|
||||
if (bindingSlot.GetBoundObject() == it->second) {
|
||||
bindingSlot.Bind(nullptr);
|
||||
}
|
||||
}
|
||||
auto bufferObject = MakeShared<FramebufferObject>(index);
|
||||
m_framebufferObjects[index] = bufferObject;
|
||||
return bufferObject;
|
||||
m_framebufferObjects.erase(it);
|
||||
}
|
||||
m_indexGenerator.Delete(index);
|
||||
}
|
||||
}
|
||||
|
||||
BindingSlot<FramebufferObject>& FramebufferState::GetBindingSlot(FramebufferTarget target) {
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
if (m_bindingSlots[i].GetTarget() == target) {
|
||||
return m_bindingSlots[i];
|
||||
}
|
||||
}
|
||||
MOBILEGL_ASSERT(false, "Invalid FramebufferTarget enum value: %d", static_cast<int>(target));
|
||||
return m_bindingSlots[0];
|
||||
}
|
||||
Bool FramebufferState::ValidateName(Uint index) const {
|
||||
return m_indexGenerator.IsValid(index);
|
||||
}
|
||||
|
||||
void FramebufferState::MarkFramebufferObjectForDeletion(Uint index) {
|
||||
if (m_indexGenerator.IsValid(index)) {
|
||||
auto it = m_framebufferObjects.find(index);
|
||||
if (it != m_framebufferObjects.end()) {
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
if (m_bindingSlots[i].GetBoundObject() == it->second) {
|
||||
m_bindingSlots[i].Bind(nullptr);
|
||||
}
|
||||
}
|
||||
m_framebufferObjects.erase(it);
|
||||
}
|
||||
m_indexGenerator.Delete(index);
|
||||
}
|
||||
}
|
||||
|
||||
Bool FramebufferState::ValidateName(Uint index) const {
|
||||
return m_indexGenerator.IsValid(index);
|
||||
}
|
||||
|
||||
Bool FramebufferState::ValidateFramebufferObject(Uint index) const {
|
||||
return m_framebufferObjects.find(index) != m_framebufferObjects.end();
|
||||
}
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
Bool FramebufferState::ValidateFramebufferObject(Uint index) const {
|
||||
return m_framebufferObjects.find(index) != m_framebufferObjects.end();
|
||||
}
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -11,28 +11,24 @@
|
||||
#include <MG_Util/Miscellany/IndexGenerator.h>
|
||||
#include "FramebufferObject.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
class FramebufferState {
|
||||
public:
|
||||
FramebufferState();
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
class FramebufferState {
|
||||
public:
|
||||
FramebufferState();
|
||||
|
||||
// FBO 0 should be created by MG_Backend when initializing the context
|
||||
SharedPtr<FramebufferObject> GetFramebufferObject(Uint index);
|
||||
Vector<Uint> GenerateNames(Uint number);
|
||||
SharedPtr<FramebufferObject> CreateFramebufferObject(Uint index);
|
||||
BindingSlot<FramebufferObject>& GetBindingSlot(FramebufferTarget target);
|
||||
void MarkFramebufferObjectForDeletion(Uint index);
|
||||
Bool ValidateName(Uint index) const;
|
||||
Bool ValidateFramebufferObject(Uint index) const;
|
||||
// FBO 0 should be created by MG_Backend when initializing the context
|
||||
const SharedPtr<FramebufferObject>& GetFramebufferObject(Uint index);
|
||||
void GenerateNames(Uint number, Vector<Uint>& framebuffers);
|
||||
const SharedPtr<FramebufferObject>& CreateFramebufferObject(Uint index);
|
||||
BindingSlot<FramebufferObject>& GetBindingSlot(FramebufferTarget target);
|
||||
void MarkFramebufferObjectForDeletion(Uint index);
|
||||
Bool ValidateName(Uint index) const;
|
||||
Bool ValidateFramebufferObject(Uint index) const;
|
||||
|
||||
private:
|
||||
UnorderedMap<Uint, SharedPtr<FramebufferObject>> m_framebufferObjects;
|
||||
IndexGenerator<Uint> m_indexGenerator;
|
||||
Array<BindingSlot<FramebufferObject>, static_cast<SizeT>(FramebufferTarget::FramebufferTargetCount)>
|
||||
m_bindingSlots;
|
||||
};
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
private:
|
||||
UnorderedMap<Uint, SharedPtr<FramebufferObject>> m_framebufferObjects;
|
||||
IndexGenerator<Uint> m_indexGenerator;
|
||||
Array<BindingSlot<FramebufferObject>, static_cast<SizeT>(FramebufferTarget::FramebufferTargetCount)>
|
||||
m_bindingSlots;
|
||||
};
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,180 +9,176 @@
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
#include "ShaderObject.h"
|
||||
#include "MG_Util/Metrics/BufferMetrics.h"
|
||||
#include "MG_Util/ShaderTranspiler/SpvcSession.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
class ProgramObject {
|
||||
public:
|
||||
ProgramObject(Uint externalIndex) : m_externalIndex(externalIndex) {}
|
||||
bool ShaderIsAttached(SharedPtr<ShaderObject> shader);
|
||||
bool AttachShader(SharedPtr<ShaderObject> shader);
|
||||
SizeT DetachShader(SharedPtr<ShaderObject> shader);
|
||||
SizeT RemoveShader(SharedPtr<ShaderObject> shader);
|
||||
void Link(Bool addDefaultFSIfMissingForRenderingPipelineProgram = false);
|
||||
void MarkAsDeleted();
|
||||
#include <MG_Util/Metrics/BufferMetrics.h>
|
||||
#include <MG_Util/ShaderTranspiler/SpvcSession.h>
|
||||
|
||||
void SetExplicitVertexInLocation(Uint index, const char* name);
|
||||
void SetExplicitFragmentOutLocation(Uint index, const char* name);
|
||||
Int GetFragmentDataLocation(const char* name);
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
class ProgramObject {
|
||||
public:
|
||||
ProgramObject(Uint externalIndex) : m_externalIndex(externalIndex) {}
|
||||
bool ShaderIsAttached(const SharedPtr<ShaderObject>& shader);
|
||||
bool AttachShader(const SharedPtr<ShaderObject>& shader);
|
||||
SizeT DetachShader(const SharedPtr<ShaderObject>& shader);
|
||||
SizeT RemoveShader(const SharedPtr<ShaderObject>& shader);
|
||||
void Link(Bool addDefaultFSIfMissingForRenderingPipelineProgram = false);
|
||||
void MarkAsDeleted();
|
||||
|
||||
Vector<SharedPtr<ShaderObject>>& GetAttachedShaders();
|
||||
const Vector<SharedPtr<ShaderObject>>& GetAttachedShaders() const;
|
||||
const String& GetInfoLog() const { return m_infoLog; }
|
||||
Int GetUniformMaxLength() const { return m_uniformNameMaxLength; }
|
||||
Uint GetUniformCount() { return m_activeUniformCount; }
|
||||
Uint GetMaxUniformLocation() const { return m_maxUniformLocation; }
|
||||
Int GetUniformLocation(const String& name) const {
|
||||
const auto it = m_uniformLocations.find(name);
|
||||
if (it == m_uniformLocations.end()) return -1;
|
||||
return (Int)it->second;
|
||||
}
|
||||
void SetExplicitVertexInLocation(Uint index, const char* name);
|
||||
void SetExplicitFragmentOutLocation(Uint index, const char* name);
|
||||
Int GetFragmentDataLocation(const char* name);
|
||||
|
||||
GLenum GetUniformType(Uint location) const {
|
||||
auto& uniform = m_program->getUniform(m_uniformIndexInTProgram[location]);
|
||||
return uniform.glDefineType;
|
||||
}
|
||||
Vector<SharedPtr<ShaderObject>>& GetAttachedShaders();
|
||||
const Vector<SharedPtr<ShaderObject>>& GetAttachedShaders() const;
|
||||
const String& GetInfoLog() const { return m_infoLog; }
|
||||
Int GetUniformMaxLength() const { return m_uniformNameMaxLength; }
|
||||
Uint GetUniformCount() const { return m_activeUniformCount; }
|
||||
Uint GetMaxUniformLocation() const { return m_maxUniformLocation; }
|
||||
Int GetUniformLocation(const String& name) const {
|
||||
const auto it = m_uniformLocations.find(name);
|
||||
if (it == m_uniformLocations.end()) return -1;
|
||||
return (Int)it->second;
|
||||
}
|
||||
|
||||
const glslang::TType* GetUniformTType(Uint location) const {
|
||||
auto& uniform = m_program->getUniform(m_uniformIndexInTProgram[location]);
|
||||
return uniform.getType();
|
||||
}
|
||||
GLenum GetUniformType(Uint location) const {
|
||||
auto& uniform = m_program->getUniform(m_uniformIndexInTProgram[location]);
|
||||
return uniform.glDefineType;
|
||||
}
|
||||
|
||||
Bool IsUniformOpaqueAtLocation(Uint location) const { return GetUniformTType(location)->isOpaque(); }
|
||||
const glslang::TType* GetUniformTType(Uint location) const {
|
||||
auto& uniform = m_program->getUniform(m_uniformIndexInTProgram[location]);
|
||||
return uniform.getType();
|
||||
}
|
||||
|
||||
const String& GetUniformName(Uint location) const {
|
||||
auto& uniform = m_program->getUniform(m_uniformIndexInTProgram[location]);
|
||||
return uniform.name;
|
||||
}
|
||||
Uint GetUniformOffset(Uint location) const { return m_uniformOffsets[location]; }
|
||||
Uint GetUniformSizesInBytes(Uint location) const {
|
||||
return MG_Util::GetGLTypeSize(GetUniformType(location));
|
||||
}
|
||||
Bool IsUniformOpaqueAtLocation(Uint location) const { return GetUniformTType(location)->isOpaque(); }
|
||||
|
||||
Int GetAttributeLocation(const String& name) {
|
||||
const auto it = std::find(m_attribs.begin(), m_attribs.end(), name);
|
||||
return (it == m_attribs.end()) ? -1 : std::distance(m_attribs.begin(), it);
|
||||
}
|
||||
GLenum GetAttribType(Uint index) const { return m_attribTypes[index]; }
|
||||
const String& GetAttribName(Uint index) const { return m_attribs[index]; }
|
||||
void* MapUBO() { return m_uboScratch.data(); }
|
||||
const void* GetUBOData() const { return m_uboScratch.data(); }
|
||||
Uint GetUBOSize() const { return static_cast<Uint>(m_uboScratch.size()); }
|
||||
const String& GetUniformName(Uint location) const {
|
||||
auto& uniform = m_program->getUniform(m_uniformIndexInTProgram[location]);
|
||||
return uniform.name;
|
||||
}
|
||||
Uint GetUniformOffset(Uint location) const { return m_uniformOffsets[location]; }
|
||||
Uint GetUniformSizesInBytes(Uint location) const { return MG_Util::GetGLTypeSize(GetUniformType(location)); }
|
||||
|
||||
void SetUniformSamplerOrImageUnitIndex(Uint location, Int unit) {
|
||||
m_uniformSamplerOrImageUnitIndex[location] = unit;
|
||||
}
|
||||
Int GetAttributeLocation(const String& name) {
|
||||
const auto it = std::find(m_attribs.begin(), m_attribs.end(), name);
|
||||
return (it == m_attribs.end()) ? -1 : (Int)std::distance(m_attribs.begin(), it);
|
||||
}
|
||||
GLenum GetAttribType(Uint index) const { return m_attribTypes[index]; }
|
||||
const String& GetAttribName(Uint index) const { return m_attribs[index]; }
|
||||
void* MapUBO() { return m_uboScratch.data(); }
|
||||
const void* GetUBOData() const { return m_uboScratch.data(); }
|
||||
Uint GetUBOSize() const { return static_cast<Uint>(m_uboScratch.size()); }
|
||||
|
||||
Int GetUniformSamplerOrImageUnitIndex(Uint location) const {
|
||||
return m_uniformSamplerOrImageUnitIndex[location];
|
||||
}
|
||||
void SetUniformSamplerOrImageUnitIndex(Uint location, Int unit) {
|
||||
m_uniformSamplerOrImageUnitIndex[location] = unit;
|
||||
}
|
||||
|
||||
Bool GetDeleteStatus() const { return m_deleteStatus; }
|
||||
Bool GetLinkStatus() const { return m_linkStatus; }
|
||||
Bool GetValidateStatus() const { return m_validateStatus; }
|
||||
Int GetActiveAtomicCounterCount() const { return m_program->getNumAtomicCounters(); }
|
||||
Int GetActiveAttributesCount() const { return m_program->getNumPipeInputs(); }
|
||||
Int GetActiveUniformBlocksCount() const { return m_program->getNumUniformBlocks(); }
|
||||
Int GetActiveAttributesMaxLength() const { return m_attribInNameMaxLength; }
|
||||
Int GetActiveUniformBlocksMaxNameLength() const { return m_uniformBlockNameMaxLength; }
|
||||
Uint GetUniformBlockIndex(const char* name) const {
|
||||
auto it = m_uniformBlockIndexByName.find(name);
|
||||
if (it != m_uniformBlockIndexByName.end()) return it->second;
|
||||
return 0xFFFFFFFFu; // GL_INVALID_INDEX
|
||||
}
|
||||
Bool IsActiveUniformBlock(Uint index) const {
|
||||
if (index >= GetActiveUniformBlocksCount()) return false;
|
||||
return true;
|
||||
}
|
||||
Uint GetUBOSizeAt(Uint index) const {
|
||||
if (!IsActiveUniformBlock(index)) return 0;
|
||||
return m_program->getUniformBlock(index).size;
|
||||
}
|
||||
Int GetUniformSamplerOrImageUnitIndex(Uint location) const {
|
||||
return m_uniformSamplerOrImageUnitIndex[location];
|
||||
}
|
||||
|
||||
const String& GetUniformBlockName(Uint index) const {
|
||||
auto& ubo = m_program->getUniformBlock(index);
|
||||
return ubo.name;
|
||||
}
|
||||
Bool GetDeleteStatus() const { return m_deleteStatus; }
|
||||
Bool GetLinkStatus() const { return m_linkStatus; }
|
||||
Bool GetValidateStatus() const { return m_validateStatus; }
|
||||
Int GetActiveAtomicCounterCount() const { return m_program->getNumAtomicCounters(); }
|
||||
Int GetActiveAttributesCount() const { return m_program->getNumPipeInputs(); }
|
||||
Int GetActiveUniformBlocksCount() const { return m_program->getNumUniformBlocks(); }
|
||||
Int GetActiveAttributesMaxLength() const { return m_attribInNameMaxLength; }
|
||||
Int GetActiveUniformBlocksMaxNameLength() const { return m_uniformBlockNameMaxLength; }
|
||||
Uint GetUniformBlockIndex(const char* name) const {
|
||||
auto it = m_uniformBlockIndexByName.find(name);
|
||||
if (it != m_uniformBlockIndexByName.end()) return it->second;
|
||||
return 0xFFFFFFFFu; // GL_INVALID_INDEX
|
||||
}
|
||||
Bool IsActiveUniformBlock(Uint index) const {
|
||||
if (index >= GetActiveUniformBlocksCount()) return false;
|
||||
return true;
|
||||
}
|
||||
Uint GetUBOSizeAt(Uint index) const {
|
||||
if (!IsActiveUniformBlock(index)) return 0;
|
||||
return m_program->getUniformBlock((Int)index).size;
|
||||
}
|
||||
|
||||
// Set by glUniformBlockBinding
|
||||
void SetUniformBlockBinding(Uint index, Uint binding) { m_uniformBlockBinding[index] = binding; }
|
||||
const String& GetUniformBlockName(Uint index) const {
|
||||
auto& ubo = m_program->getUniformBlock((Int)index);
|
||||
return ubo.name;
|
||||
}
|
||||
|
||||
Uint GetUniformBlockBinding(Uint index) const { return m_uniformBlockBinding[index]; }
|
||||
// Set by glUniformBlockBinding
|
||||
void SetUniformBlockBinding(Uint index, Uint binding) { m_uniformBlockBinding[index] = (Int)binding; }
|
||||
|
||||
Vector<Vector<unsigned>>& GetGeneratedSpirv() { return m_generatedSpirv; }
|
||||
const Vector<Vector<unsigned>>& GetGeneratedSpirv() const { return m_generatedSpirv; }
|
||||
Uint GetUniformBlockBinding(Uint index) const { return m_uniformBlockBinding[index]; }
|
||||
|
||||
Int GetShaderIndexByStage(ShaderStage stage) const {
|
||||
auto it = std::find_if(m_shaders.begin(), m_shaders.end(),
|
||||
[stage](const SharedPtr<ShaderObject>& shader) { return shader->GetShaderStage() == stage; });
|
||||
return it == m_shaders.end() ? -1 : std::distance(m_shaders.begin(), it);
|
||||
}
|
||||
Vector<Vector<unsigned>>& GetGeneratedSpirv() { return m_generatedSpirv; }
|
||||
const Vector<Vector<unsigned>>& GetGeneratedSpirv() const { return m_generatedSpirv; }
|
||||
|
||||
Uint GetExternalIndex() const { return m_externalIndex; }
|
||||
Int GetShaderIndexByStage(ShaderStage stage) const {
|
||||
auto it = std::find_if(m_shaders.begin(), m_shaders.end(), [stage](const SharedPtr<ShaderObject>& shader) {
|
||||
return shader->GetShaderStage() == stage;
|
||||
});
|
||||
return it == m_shaders.end() ? -1 : (Int)std::distance(m_shaders.begin(), it);
|
||||
}
|
||||
|
||||
// const UnorderedMap<String, Uint>& GetAttribLocationMap() const { return
|
||||
// m_attribLocation; }
|
||||
Uint GetExternalIndex() const { return m_externalIndex; }
|
||||
|
||||
private:
|
||||
void DoReflection();
|
||||
void GenerateBinary();
|
||||
void WaitUntilGenerationCompleted();
|
||||
void AddDefaultFragmentShaderIfMissing();
|
||||
// const UnorderedMap<String, Uint>& GetAttribLocationMap() const { return
|
||||
// m_attribLocation; }
|
||||
|
||||
const Uint m_externalIndex = 0;
|
||||
Vector<SharedPtr<ShaderObject>> m_shaders;
|
||||
Vector<SharedPtr<ShaderObject>> m_detachedShaders; // Store detached shaders and remove on next link
|
||||
private:
|
||||
void DoReflection();
|
||||
void GenerateBinary();
|
||||
void WaitUntilGenerationCompleted() const;
|
||||
void AddDefaultFragmentShaderIfMissing();
|
||||
|
||||
SharedPtr<glslang::TProgram> m_program;
|
||||
const Uint m_externalIndex = 0;
|
||||
Vector<SharedPtr<ShaderObject>> m_shaders;
|
||||
Vector<SharedPtr<ShaderObject>> m_detachedShaders; // Store detached shaders and remove on next link
|
||||
|
||||
Vector<Vector<unsigned>> m_generatedSpirv;
|
||||
SharedPtr<glslang::TProgram> m_program;
|
||||
|
||||
// Attributes (Vertex in)
|
||||
UnorderedMap<String, Uint> m_explicitAttribLocations;
|
||||
Vector<String> m_attribs;
|
||||
Vector<GLenum> m_attribTypes;
|
||||
// For SpvcSession::SetVertexAttribLocation()
|
||||
// UnorderedMap<String, Uint> m_attribLocation;
|
||||
Vector<Vector<unsigned>> m_generatedSpirv;
|
||||
|
||||
// FragData (Frag out)
|
||||
UnorderedMap<String, Uint> m_explicitFragDataLocation;
|
||||
// Attributes (Vertex in)
|
||||
UnorderedMap<String, Uint> m_explicitAttribLocations;
|
||||
Vector<String> m_attribs;
|
||||
Vector<GLenum> m_attribTypes;
|
||||
// For SpvcSession::SetVertexAttribLocation()
|
||||
// UnorderedMap<String, Uint> m_attribLocation;
|
||||
|
||||
// Uniforms
|
||||
UnorderedMap<String, Uint> m_uniformLocations;
|
||||
// Ordered by location,
|
||||
// aka. m_uniformIndexInTProgram[loc] == "uniform index of TProgram at location `loc`"
|
||||
Vector<Int> m_uniformIndexInTProgram;
|
||||
// ditto. Will be set at glUniform1i
|
||||
Vector<Int> m_uniformSamplerOrImageUnitIndex;
|
||||
// FragData (Frag out)
|
||||
UnorderedMap<String, Uint> m_explicitFragDataLocation;
|
||||
|
||||
// Ordered by uniform block index
|
||||
// index is DIFFERENT from binding!!!
|
||||
//
|
||||
// Let's define UniformBlockIndex == the order at glslang getUniformBlock()
|
||||
// aka `i = glGetUniformBlockIndex(prog, "BlockName")` implies:
|
||||
// `prog->getUniformBlock(i) == "BlockName"`
|
||||
UnorderedMap<String, Uint> m_uniformBlockIndexByName;
|
||||
Vector<Int> m_uniformBlockBinding;
|
||||
// Uniforms
|
||||
UnorderedMap<String, Uint> m_uniformLocations;
|
||||
// Ordered by location,
|
||||
// aka. m_uniformIndexInTProgram[loc] == "uniform index of TProgram at location `loc`"
|
||||
Vector<Int> m_uniformIndexInTProgram;
|
||||
// ditto. Will be set at glUniform1i
|
||||
Vector<Int> m_uniformSamplerOrImageUnitIndex;
|
||||
|
||||
// Need to be reflected after linking of SPIR-V binary
|
||||
Vector<Uint> m_uniformOffsets;
|
||||
Vector<Uint> m_uniformSizesInBytes;
|
||||
Vector<Uint8> m_uboScratch;
|
||||
// Ordered by uniform block index
|
||||
// index is DIFFERENT from binding!!!
|
||||
//
|
||||
// Let's define UniformBlockIndex == the order at glslang getUniformBlock()
|
||||
// aka `i = glGetUniformBlockIndex(prog, "BlockName")` implies:
|
||||
// `prog->getUniformBlock(i) == "BlockName"`
|
||||
UnorderedMap<String, Uint> m_uniformBlockIndexByName;
|
||||
Vector<Int> m_uniformBlockBinding;
|
||||
|
||||
Uint m_activeUniformCount = 0;
|
||||
Uint m_maxUniformLocation = 0;
|
||||
Int m_uniformNameMaxLength = 0;
|
||||
Int m_attribInNameMaxLength = 0;
|
||||
Int m_uniformBlockNameMaxLength = 0;
|
||||
// Need to be reflected after linking of SPIR-V binary
|
||||
Vector<Uint> m_uniformOffsets;
|
||||
Vector<Uint> m_uniformSizesInBytes;
|
||||
Vector<Uint8> m_uboScratch;
|
||||
|
||||
String m_infoLog;
|
||||
Bool m_deleteStatus = false;
|
||||
Bool m_linkStatus = false;
|
||||
Bool m_validateStatus = true;
|
||||
};
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
Uint m_activeUniformCount = 0;
|
||||
Uint m_maxUniformLocation = 0;
|
||||
Int m_uniformNameMaxLength = 0;
|
||||
Int m_attribInNameMaxLength = 0;
|
||||
Int m_uniformBlockNameMaxLength = 0;
|
||||
|
||||
String m_infoLog;
|
||||
Bool m_deleteStatus = false;
|
||||
Bool m_linkStatus = false;
|
||||
Bool m_validateStatus = true;
|
||||
};
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -8,73 +8,71 @@
|
||||
|
||||
#include "ProgramState.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
Uint ProgramState::CreateProgram() {
|
||||
Uint programId = 0;
|
||||
m_programIndexGenerator.Generate(1, &programId);
|
||||
EnsureIndexAvail(programId, m_programObjects);
|
||||
auto programObject = MakeShared<ProgramObject>(programId);
|
||||
if (programObject == nullptr) return 0;
|
||||
m_programObjects[programId] = programObject;
|
||||
return programId;
|
||||
}
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
Uint ProgramState::CreateProgram() {
|
||||
Uint programId = 0;
|
||||
m_programIndexGenerator.Generate(1, &programId);
|
||||
EnsureIndexAvail(programId, m_programObjects);
|
||||
auto programObject = MakeShared<ProgramObject>(programId);
|
||||
if (programObject == nullptr) return 0;
|
||||
m_programObjects[programId] = programObject;
|
||||
return programId;
|
||||
}
|
||||
|
||||
SharedPtr<ProgramObject> ProgramState::GetProgramObject(const Uint id) {
|
||||
if (!CheckIndexAvail(id, m_programObjects)) return nullptr; // FIXME: add error reporting here
|
||||
return m_programObjects[id];
|
||||
}
|
||||
const SharedPtr<ProgramObject>& ProgramState::GetProgramObject(const Uint id) {
|
||||
static SharedPtr<ProgramObject> nullProgramObject = nullptr;
|
||||
if (!CheckIndexAvail(id, m_programObjects)) return nullProgramObject; // FIXME: add error reporting here
|
||||
return m_programObjects[id];
|
||||
}
|
||||
|
||||
void ProgramState::MarkProgramObjectForDeletion(const Uint program) {
|
||||
if (!CheckIndexAvail(program, m_programObjects)) return; // FIXME: add error reporting here
|
||||
auto& programObject = m_programObjects[program];
|
||||
if (programObject != nullptr) {
|
||||
programObject->MarkAsDeleted();
|
||||
programObject.reset();
|
||||
m_programIndexGenerator.Delete(program);
|
||||
}
|
||||
}
|
||||
void ProgramState::MarkProgramObjectForDeletion(const Uint program) {
|
||||
if (!CheckIndexAvail(program, m_programObjects)) return; // FIXME: add error reporting here
|
||||
auto& programObject = m_programObjects[program];
|
||||
if (programObject != nullptr) {
|
||||
programObject->MarkAsDeleted();
|
||||
programObject.reset();
|
||||
m_programIndexGenerator.Delete(program);
|
||||
}
|
||||
}
|
||||
|
||||
Bool ProgramState::ValidateProgramObject(const Uint program) const {
|
||||
return CheckIndexAvail(program, m_programObjects) && m_programObjects[program] != nullptr;
|
||||
}
|
||||
Bool ProgramState::ValidateProgramObject(const Uint program) const {
|
||||
return CheckIndexAvail(program, m_programObjects) && m_programObjects[program] != nullptr;
|
||||
}
|
||||
|
||||
void ProgramState::UseProgram(Uint program) {
|
||||
if (program == 0) m_currentProgram.reset();
|
||||
void ProgramState::UseProgram(Uint program) {
|
||||
if (program == 0) m_currentProgram.reset();
|
||||
|
||||
if (!CheckIndexAvail(program, m_programObjects)) return;
|
||||
m_currentProgram = m_programObjects[program];
|
||||
}
|
||||
if (!CheckIndexAvail(program, m_programObjects)) return;
|
||||
m_currentProgram = m_programObjects[program];
|
||||
}
|
||||
|
||||
Uint ProgramState::CreateShader(ShaderStage stage) {
|
||||
Uint shaderId = 0;
|
||||
m_shaderIndexGenerator.Generate(1, &shaderId);
|
||||
EnsureIndexAvail(shaderId, m_shaderObjects);
|
||||
auto shaderObject = MakeShared<ShaderObject>(stage, shaderId);
|
||||
if (shaderObject == nullptr) return 0;
|
||||
m_shaderObjects[shaderId] = shaderObject;
|
||||
return shaderId;
|
||||
}
|
||||
Uint ProgramState::CreateShader(ShaderStage stage) {
|
||||
Uint shaderId = 0;
|
||||
m_shaderIndexGenerator.Generate(1, &shaderId);
|
||||
EnsureIndexAvail(shaderId, m_shaderObjects);
|
||||
auto shaderObject = MakeShared<ShaderObject>(stage, shaderId);
|
||||
if (shaderObject == nullptr) return 0;
|
||||
m_shaderObjects[shaderId] = shaderObject;
|
||||
return shaderId;
|
||||
}
|
||||
|
||||
SharedPtr<ShaderObject> ProgramState::GetShaderObject(const Uint shader) {
|
||||
if (!CheckIndexAvail(shader, m_shaderObjects)) return nullptr;
|
||||
return m_shaderObjects[shader];
|
||||
}
|
||||
const SharedPtr<ShaderObject>& ProgramState::GetShaderObject(const Uint shader) {
|
||||
static SharedPtr<ShaderObject> nullShaderObject = nullptr;
|
||||
if (!CheckIndexAvail(shader, m_shaderObjects)) return nullShaderObject;
|
||||
return m_shaderObjects[shader];
|
||||
}
|
||||
|
||||
void ProgramState::MarkShaderObjectForDeletion(Uint shader) {
|
||||
if (!CheckIndexAvail(shader, m_shaderObjects)) return;
|
||||
auto& shaderObject = m_shaderObjects[shader];
|
||||
if (shaderObject != nullptr) {
|
||||
m_shaderObjects[shader]->MarkAsDeleted();
|
||||
m_shaderObjects[shader].reset();
|
||||
m_shaderIndexGenerator.Delete(shader);
|
||||
}
|
||||
}
|
||||
void ProgramState::MarkShaderObjectForDeletion(Uint shader) {
|
||||
if (!CheckIndexAvail(shader, m_shaderObjects)) return;
|
||||
auto& shaderObject = m_shaderObjects[shader];
|
||||
if (shaderObject != nullptr) {
|
||||
m_shaderObjects[shader]->MarkAsDeleted();
|
||||
m_shaderObjects[shader].reset();
|
||||
m_shaderIndexGenerator.Delete(shader);
|
||||
}
|
||||
}
|
||||
|
||||
Bool ProgramState::ValidateShaderObject(Uint shader) const {
|
||||
return CheckIndexAvail(shader, m_shaderObjects) && m_shaderObjects[shader] != nullptr;
|
||||
}
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
Bool ProgramState::ValidateShaderObject(Uint shader) const {
|
||||
return CheckIndexAvail(shader, m_shaderObjects) && m_shaderObjects[shader] != nullptr;
|
||||
}
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -11,49 +11,45 @@
|
||||
#include <MG_Util/Miscellany/IndexGenerator.h>
|
||||
#include "ProgramObject.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
class ProgramState {
|
||||
public:
|
||||
// This function WILL actually create the program object.
|
||||
// To retrieve created program object, use GetProgramObject()
|
||||
Uint CreateProgram();
|
||||
SharedPtr<ProgramObject> GetProgramObject(Uint id);
|
||||
void MarkProgramObjectForDeletion(Uint program);
|
||||
Bool ValidateProgramObject(Uint program) const;
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
class ProgramState {
|
||||
public:
|
||||
// This function WILL actually create the program object.
|
||||
// To retrieve created program object, use GetProgramObject()
|
||||
Uint CreateProgram();
|
||||
const SharedPtr<ProgramObject>& GetProgramObject(Uint id);
|
||||
void MarkProgramObjectForDeletion(Uint program);
|
||||
Bool ValidateProgramObject(Uint program) const;
|
||||
|
||||
void UseProgram(Uint program);
|
||||
void UseProgram(Uint program);
|
||||
|
||||
Uint CreateShader(ShaderStage stage);
|
||||
SharedPtr<ShaderObject> GetShaderObject(Uint shader);
|
||||
void MarkShaderObjectForDeletion(Uint shader);
|
||||
Bool ValidateShaderObject(Uint shader) const;
|
||||
Uint CreateShader(ShaderStage stage);
|
||||
const SharedPtr<ShaderObject>& GetShaderObject(Uint shader);
|
||||
void MarkShaderObjectForDeletion(Uint shader);
|
||||
Bool ValidateShaderObject(Uint shader) const;
|
||||
|
||||
SharedPtr<ProgramObject> GetCurrentProgram() const { return m_currentProgram; }
|
||||
const SharedPtr<ProgramObject>& GetCurrentProgram() const { return m_currentProgram; }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
static Bool CheckIndexAvail(const SizeT idx, const Vector<T>& vec) {
|
||||
return idx < vec.size();
|
||||
}
|
||||
private:
|
||||
template <typename T>
|
||||
static Bool CheckIndexAvail(const SizeT idx, const Vector<T>& vec) {
|
||||
return idx < vec.size();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void EnsureIndexAvail(const SizeT idx, Vector<T>& vec) {
|
||||
if (CheckIndexAvail(idx, vec)) return;
|
||||
template <typename T>
|
||||
static void EnsureIndexAvail(const SizeT idx, Vector<T>& vec) {
|
||||
if (CheckIndexAvail(idx, vec)) return;
|
||||
|
||||
vec.reserve(std::bit_ceil(idx));
|
||||
vec.resize(idx + 1);
|
||||
}
|
||||
vec.reserve(std::bit_ceil(idx));
|
||||
vec.resize(idx + 1);
|
||||
}
|
||||
|
||||
IndexGenerator<Uint> m_programIndexGenerator;
|
||||
Vector<SharedPtr<ProgramObject>> m_programObjects;
|
||||
IndexGenerator<Uint> m_programIndexGenerator;
|
||||
Vector<SharedPtr<ProgramObject>> m_programObjects;
|
||||
|
||||
IndexGenerator<Uint> m_shaderIndexGenerator;
|
||||
Vector<SharedPtr<ShaderObject>> m_shaderObjects;
|
||||
IndexGenerator<Uint> m_shaderIndexGenerator;
|
||||
Vector<SharedPtr<ShaderObject>> m_shaderObjects;
|
||||
|
||||
SharedPtr<ProgramObject> m_currentProgram;
|
||||
};
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
SharedPtr<ProgramObject> m_currentProgram;
|
||||
};
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -13,43 +13,40 @@
|
||||
#include <MG_Util/ShaderTranspiler/ShaderSourceProcessor.h>
|
||||
#include <MG_Util/ShaderTranspiler/glslang/UniformTraverser.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
void ShaderObject::SetShaderSource(const String& source) {
|
||||
m_source = source;
|
||||
}
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
void ShaderObject::SetShaderSource(const String& source) {
|
||||
m_source = source;
|
||||
}
|
||||
|
||||
void ShaderObject::SetShaderSource(String&& source) {
|
||||
m_source = Move(source);
|
||||
}
|
||||
void ShaderObject::SetShaderSource(String&& source) {
|
||||
m_source = Move(source);
|
||||
}
|
||||
|
||||
void ShaderObject::Compile() {
|
||||
using namespace MG_Util::ShaderTranspiler;
|
||||
MG_Util::ShaderTranspiler::PreprocessShaderSource(m_stage, m_source);
|
||||
void ShaderObject::Compile() {
|
||||
using namespace MG_Util::ShaderTranspiler;
|
||||
MG_Util::ShaderTranspiler::PreprocessShaderSource(m_stage, m_source);
|
||||
|
||||
// Compile for OpenGL here, so that we can do validation and link
|
||||
// like a real OpenGL driver at linking stage
|
||||
// Will compile for other backends later.
|
||||
ShaderAttrib attrib{
|
||||
.shaderType = MG_Util::ConvertShaderStageToGLEnum(m_stage), .sourceStr = m_source, .flags = ShaderCompileBits::CompileForOpenGL};
|
||||
// Compile for OpenGL here, so that we can do validation and link
|
||||
// like a real OpenGL driver at linking stage
|
||||
// Will compile for other backends later.
|
||||
ShaderAttrib attrib{.shaderType = MG_Util::ConvertShaderStageToGLEnum(m_stage),
|
||||
.sourceStr = m_source,
|
||||
.flags = ShaderCompileBits::CompileForOpenGL};
|
||||
|
||||
auto result = ShaderCompiler::CompileShader(attrib);
|
||||
if (result) {
|
||||
m_compileStatus = true;
|
||||
m_shader = result.value();
|
||||
} else {
|
||||
m_compileStatus = false;
|
||||
m_infoLog = result.error().log;
|
||||
MGLOG_D("ShaderObject::Compile: Shader %d compilation failed.\nSource:\n%s\nInfoLog:\n%s\nSetting "
|
||||
"m_compileStatus = false as a result.",
|
||||
m_externalIndex, m_source.c_str(), m_infoLog.c_str());
|
||||
}
|
||||
}
|
||||
auto result = ShaderCompiler::CompileShader(attrib);
|
||||
if (result) {
|
||||
m_compileStatus = true;
|
||||
m_shader = result.value();
|
||||
} else {
|
||||
m_compileStatus = false;
|
||||
m_infoLog = result.error().log;
|
||||
MGLOG_D("ShaderObject::Compile: Shader %d compilation failed.\nSource:\n%s\nInfoLog:\n%s\nSetting "
|
||||
"m_compileStatus = false as a result.",
|
||||
m_externalIndex, m_source.c_str(), m_infoLog.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderObject::MarkAsDeleted() {
|
||||
m_deleteStatus = true;
|
||||
}
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
void ShaderObject::MarkAsDeleted() {
|
||||
m_deleteStatus = true;
|
||||
}
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -21,37 +21,35 @@ namespace MobileGL {
|
||||
Unknown = -1
|
||||
};
|
||||
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
class ShaderObject {
|
||||
public:
|
||||
ShaderObject(const ShaderStage stage, Uint externalIndex)
|
||||
: m_stage(stage), m_externalIndex(externalIndex) {}
|
||||
void SetShaderSource(const String& source);
|
||||
void SetShaderSource(String&& source);
|
||||
void Compile();
|
||||
void MarkAsDeleted();
|
||||
namespace MG_State::GLState {
|
||||
class ShaderObject {
|
||||
public:
|
||||
ShaderObject(const ShaderStage stage, Uint externalIndex)
|
||||
: m_stage(stage), m_externalIndex(externalIndex) {}
|
||||
void SetShaderSource(const String& source);
|
||||
void SetShaderSource(String&& source);
|
||||
void Compile();
|
||||
void MarkAsDeleted();
|
||||
|
||||
Uint GetExternalIndex() const { return m_externalIndex; }
|
||||
ShaderStage GetShaderStage() const { return m_stage; }
|
||||
const String& GetShaderSource() const { return m_source; }
|
||||
SharedPtr<glslang::TShader> GetCompiledShader() const { return m_shader; }
|
||||
const String& GetInfoLog() const { return m_infoLog; }
|
||||
const UnorderedMap<String, Uint>& GetUniformLocations() const { return m_uniforms; }
|
||||
Bool GetCompileStatus() const { return m_compileStatus; }
|
||||
Bool GetDeleteStatus() const { return m_deleteStatus; }
|
||||
Uint GetExternalIndex() const { return m_externalIndex; }
|
||||
ShaderStage GetShaderStage() const { return m_stage; }
|
||||
const String& GetShaderSource() const { return m_source; }
|
||||
const SharedPtr<glslang::TShader>& GetCompiledShader() const { return m_shader; }
|
||||
const String& GetInfoLog() const { return m_infoLog; }
|
||||
const UnorderedMap<String, Uint>& GetUniformLocations() const { return m_uniforms; }
|
||||
Bool GetCompileStatus() const { return m_compileStatus; }
|
||||
Bool GetDeleteStatus() const { return m_deleteStatus; }
|
||||
|
||||
private:
|
||||
const Uint m_externalIndex = 0;
|
||||
const ShaderStage m_stage;
|
||||
String m_source;
|
||||
SharedPtr<glslang::TShader> m_shader;
|
||||
UnorderedMap<String, Uint> m_uniforms;
|
||||
private:
|
||||
const Uint m_externalIndex = 0;
|
||||
const ShaderStage m_stage;
|
||||
String m_source;
|
||||
SharedPtr<glslang::TShader> m_shader;
|
||||
UnorderedMap<String, Uint> m_uniforms;
|
||||
|
||||
String m_infoLog;
|
||||
Bool m_deleteStatus = false;
|
||||
Bool m_compileStatus = false;
|
||||
};
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
String m_infoLog;
|
||||
Bool m_deleteStatus = false;
|
||||
Bool m_compileStatus = false;
|
||||
};
|
||||
} // namespace MG_State::GLState
|
||||
} // namespace MobileGL
|
||||
|
||||
@@ -38,8 +38,8 @@ namespace MobileGL {
|
||||
void RenderState::SetCapability(CapabilityInput cap, Bool enabled) {
|
||||
#define SET_CAPABILITY(capability, flag) \
|
||||
case CapabilityInput::capability: \
|
||||
if (m_parameters.capability##Enabled == flag) break; \
|
||||
m_parameters.capability##Enabled = flag; \
|
||||
if (m_parameters.capability##Enabled == (flag)) break; \
|
||||
m_parameters.capability##Enabled = (flag); \
|
||||
++m_version; \
|
||||
break;
|
||||
|
||||
@@ -195,7 +195,7 @@ namespace MobileGL {
|
||||
++m_version;
|
||||
}
|
||||
|
||||
const BoolVec4 RenderState::GetColorMask() const {
|
||||
BoolVec4 RenderState::GetColorMask() const {
|
||||
return m_parameters.ColorMask;
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ namespace MobileGL {
|
||||
++m_version;
|
||||
}
|
||||
|
||||
Int RenderState::GetClearStencil() const {
|
||||
Uint32 RenderState::GetClearStencil() const {
|
||||
return m_parameters.ClearStencil;
|
||||
}
|
||||
|
||||
@@ -237,8 +237,8 @@ namespace MobileGL {
|
||||
void RenderState::SetPixelStoreParam(PixelStoreParam param, Int value) {
|
||||
#define SET_PIXEL_STORE_PARAM(paramNameHead, paramNameTail, val) \
|
||||
case PixelStoreParam::paramNameHead##paramNameTail: \
|
||||
if (m_pixelStore##paramNameHead##Parameters.paramNameTail == val) break; \
|
||||
m_pixelStore##paramNameHead##Parameters.paramNameTail = val; \
|
||||
if (m_pixelStore##paramNameHead##Parameters.paramNameTail == (val)) break; \
|
||||
m_pixelStore##paramNameHead##Parameters.paramNameTail = (val); \
|
||||
break;
|
||||
|
||||
switch (param) {
|
||||
|
||||
@@ -154,7 +154,7 @@ namespace MobileGL {
|
||||
// Clear State
|
||||
FloatVec4 ClearColor = FloatVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
Float ClearDepth = 1.0f;
|
||||
Int ClearStencil = 0;
|
||||
Uint32 ClearStencil = 0;
|
||||
|
||||
// Cull Face
|
||||
Bool CullFaceEnabled = false;
|
||||
@@ -201,7 +201,7 @@ namespace MobileGL {
|
||||
|
||||
// Color Mask
|
||||
void SetColorMask(BoolVec4 mask);
|
||||
const BoolVec4 GetColorMask() const;
|
||||
BoolVec4 GetColorMask() const;
|
||||
|
||||
// Clear State
|
||||
void SetClearColor(FloatVec4 color);
|
||||
@@ -209,7 +209,7 @@ namespace MobileGL {
|
||||
void SetClearDepth(Float depth);
|
||||
Float GetClearDepth() const;
|
||||
void SetClearStencil(Int stencil);
|
||||
Int GetClearStencil() const;
|
||||
Uint32 GetClearStencil() const;
|
||||
|
||||
// Pixel Store
|
||||
void SetPixelStoreParam(PixelStoreParam param, Int value);
|
||||
|
||||
@@ -7,68 +7,67 @@
|
||||
// End of Source File Header
|
||||
|
||||
#include "RenderbufferState.h"
|
||||
#include "MG_Util/Types.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
RenderbufferState::RenderbufferState() : m_indexGenerator(1024, 1) {
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
m_bindingSlots[i] = BindingSlot<RenderbufferObject>(static_cast<RenderbufferTarget>(i));
|
||||
}
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
RenderbufferState::RenderbufferState() : m_indexGenerator(1024, 1) {
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
m_bindingSlots[i] = BindingSlot<RenderbufferObject>(static_cast<RenderbufferTarget>(i));
|
||||
}
|
||||
}
|
||||
|
||||
const SharedPtr<RenderbufferObject>& RenderbufferState::GetRenderbufferObject(Uint index) {
|
||||
auto it = m_renderbufferObjects.find(index);
|
||||
if (it != m_renderbufferObjects.end()) {
|
||||
return it->second;
|
||||
}
|
||||
static SharedPtr<RenderbufferObject> nullRenderbufferObject = nullptr;
|
||||
return nullRenderbufferObject;
|
||||
}
|
||||
|
||||
void RenderbufferState::GenerateNames(Uint number, Vector<Uint>& renderbuffers) {
|
||||
renderbuffers.resize(number);
|
||||
m_indexGenerator.Generate(number, renderbuffers.data());
|
||||
}
|
||||
|
||||
const SharedPtr<RenderbufferObject>& RenderbufferState::CreateRenderbufferObject(Uint index) {
|
||||
auto& bufferObject = m_renderbufferObjects[index];
|
||||
if (!bufferObject) {
|
||||
bufferObject = MakeShared<RenderbufferObject>(index);
|
||||
}
|
||||
return bufferObject;
|
||||
}
|
||||
|
||||
BindingSlot<RenderbufferObject>& RenderbufferState::GetBindingSlot(RenderbufferTarget target) {
|
||||
for (auto& bindingSlot : m_bindingSlots) {
|
||||
if (bindingSlot.GetTarget() == target) {
|
||||
return bindingSlot;
|
||||
}
|
||||
}
|
||||
MOBILEGL_ASSERT(false, "Invalid RenderbufferTarget enum value: %d", static_cast<int>(target));
|
||||
return m_bindingSlots[0];
|
||||
}
|
||||
|
||||
SharedPtr<RenderbufferObject> RenderbufferState::GetRenderbufferObject(Uint index) {
|
||||
auto it = m_renderbufferObjects.find(index);
|
||||
if (it != m_renderbufferObjects.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Vector<Uint> RenderbufferState::GenerateNames(Uint number) {
|
||||
Vector<Uint> buffers(number);
|
||||
m_indexGenerator.Generate(number, buffers.data());
|
||||
return buffers;
|
||||
}
|
||||
|
||||
SharedPtr<RenderbufferObject> RenderbufferState::CreateRenderbufferObject(Uint index) {
|
||||
auto bufferObject = MakeShared<RenderbufferObject>(index);
|
||||
m_renderbufferObjects[index] = bufferObject;
|
||||
return bufferObject;
|
||||
}
|
||||
|
||||
BindingSlot<RenderbufferObject>& RenderbufferState::GetBindingSlot(RenderbufferTarget target) {
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
if (m_bindingSlots[i].GetTarget() == target) {
|
||||
return m_bindingSlots[i];
|
||||
void RenderbufferState::MarkRenderbufferObjectForDeletion(Uint index) {
|
||||
if (m_indexGenerator.IsValid(index)) {
|
||||
auto it = m_renderbufferObjects.find(index);
|
||||
if (it != m_renderbufferObjects.end()) {
|
||||
for (auto& bindingSlot : m_bindingSlots) {
|
||||
if (bindingSlot.GetBoundObject() == it->second) {
|
||||
bindingSlot.Bind(nullptr);
|
||||
}
|
||||
}
|
||||
MOBILEGL_ASSERT(false, "Invalid RenderbufferTarget enum value: %d", static_cast<int>(target));
|
||||
return m_bindingSlots[0];
|
||||
m_renderbufferObjects.erase(it);
|
||||
}
|
||||
m_indexGenerator.Delete(index);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderbufferState::MarkRenderbufferObjectForDeletion(Uint index) {
|
||||
if (m_indexGenerator.IsValid(index)) {
|
||||
auto it = m_renderbufferObjects.find(index);
|
||||
if (it != m_renderbufferObjects.end()) {
|
||||
for (SizeT i = 0; i < m_bindingSlots.size(); ++i) {
|
||||
if (m_bindingSlots[i].GetBoundObject() == it->second) {
|
||||
m_bindingSlots[i].Bind(nullptr);
|
||||
}
|
||||
}
|
||||
m_renderbufferObjects.erase(it);
|
||||
}
|
||||
m_indexGenerator.Delete(index);
|
||||
}
|
||||
}
|
||||
Bool RenderbufferState::ValidateName(Uint index) const {
|
||||
return m_indexGenerator.IsValid(index);
|
||||
}
|
||||
|
||||
Bool RenderbufferState::ValidateName(Uint index) const {
|
||||
return m_indexGenerator.IsValid(index);
|
||||
}
|
||||
|
||||
Bool RenderbufferState::ValidateRenderbufferObject(Uint index) const {
|
||||
return m_renderbufferObjects.find(index) != m_renderbufferObjects.end();
|
||||
}
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
Bool RenderbufferState::ValidateRenderbufferObject(Uint index) const {
|
||||
return m_renderbufferObjects.find(index) != m_renderbufferObjects.end();
|
||||
}
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -11,27 +11,23 @@
|
||||
#include <MG_Util/Miscellany/IndexGenerator.h>
|
||||
#include "RenderbufferObject.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
class RenderbufferState {
|
||||
public:
|
||||
RenderbufferState();
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
class RenderbufferState {
|
||||
public:
|
||||
RenderbufferState();
|
||||
|
||||
SharedPtr<RenderbufferObject> GetRenderbufferObject(Uint index);
|
||||
Vector<Uint> GenerateNames(Uint number);
|
||||
SharedPtr<RenderbufferObject> CreateRenderbufferObject(Uint index);
|
||||
BindingSlot<RenderbufferObject>& GetBindingSlot(RenderbufferTarget target);
|
||||
void MarkRenderbufferObjectForDeletion(Uint index);
|
||||
Bool ValidateName(Uint index) const;
|
||||
Bool ValidateRenderbufferObject(Uint index) const;
|
||||
const SharedPtr<RenderbufferObject>& GetRenderbufferObject(Uint index);
|
||||
void GenerateNames(Uint number, Vector<Uint>& renderbuffers);
|
||||
const SharedPtr<RenderbufferObject>& CreateRenderbufferObject(Uint index);
|
||||
BindingSlot<RenderbufferObject>& GetBindingSlot(RenderbufferTarget target);
|
||||
void MarkRenderbufferObjectForDeletion(Uint index);
|
||||
Bool ValidateName(Uint index) const;
|
||||
Bool ValidateRenderbufferObject(Uint index) const;
|
||||
|
||||
private:
|
||||
UnorderedMap<Uint, SharedPtr<RenderbufferObject>> m_renderbufferObjects;
|
||||
IndexGenerator<Uint> m_indexGenerator;
|
||||
Array<BindingSlot<RenderbufferObject>, static_cast<SizeT>(RenderbufferTarget::RenderbufferTargetCount)>
|
||||
m_bindingSlots;
|
||||
};
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
private:
|
||||
UnorderedMap<Uint, SharedPtr<RenderbufferObject>> m_renderbufferObjects;
|
||||
IndexGenerator<Uint> m_indexGenerator;
|
||||
Array<BindingSlot<RenderbufferObject>, static_cast<SizeT>(RenderbufferTarget::RenderbufferTargetCount)>
|
||||
m_bindingSlots;
|
||||
};
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -8,42 +8,38 @@
|
||||
|
||||
#include "SamplerState.h"
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
SamplerState::SamplerState() : m_indexGenerator(1024, 1) {}
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
SamplerState::SamplerState() : m_indexGenerator(1024, 1) {}
|
||||
|
||||
Vector<Uint> SamplerState::GenerateNames(Uint number) {
|
||||
Vector<Uint> names(number);
|
||||
m_indexGenerator.Generate(number, names.data());
|
||||
return names;
|
||||
}
|
||||
void SamplerState::GenerateNames(Uint number, Vector<Uint>& samplers) {
|
||||
samplers.resize(number);
|
||||
m_indexGenerator.Generate(number, samplers.data());
|
||||
}
|
||||
|
||||
SharedPtr<SamplerObject> SamplerState::GetSamplerObject(Uint index) {
|
||||
auto it = m_samplerObjects.find(index);
|
||||
return it != m_samplerObjects.end() ? it->second : nullptr;
|
||||
}
|
||||
const SharedPtr<SamplerObject>& SamplerState::GetSamplerObject(Uint index) {
|
||||
auto it = m_samplerObjects.find(index);
|
||||
static SharedPtr<SamplerObject> nullSamplerObject = nullptr;
|
||||
return it != m_samplerObjects.end() ? it->second : nullSamplerObject;
|
||||
}
|
||||
|
||||
SharedPtr<SamplerObject> SamplerState::CreateSamplerObject(Uint index) {
|
||||
auto sampler = MakeShared<SamplerObject>(index);
|
||||
m_samplerObjects[index] = sampler;
|
||||
return sampler;
|
||||
}
|
||||
const SharedPtr<SamplerObject>& SamplerState::CreateSamplerObject(Uint index) {
|
||||
auto& sampler = m_samplerObjects[index];
|
||||
sampler = MakeShared<SamplerObject>(index);
|
||||
return sampler;
|
||||
}
|
||||
|
||||
void SamplerState::MarkSamplerObjectForDeletion(Uint index) {
|
||||
if (m_indexGenerator.IsValid(index)) {
|
||||
m_samplerObjects.erase(index);
|
||||
m_indexGenerator.Delete(index);
|
||||
}
|
||||
}
|
||||
void SamplerState::MarkSamplerObjectForDeletion(Uint index) {
|
||||
if (m_indexGenerator.IsValid(index)) {
|
||||
m_samplerObjects.erase(index);
|
||||
m_indexGenerator.Delete(index);
|
||||
}
|
||||
}
|
||||
|
||||
Bool SamplerState::ValidateName(Uint index) const {
|
||||
return m_indexGenerator.IsValid(index);
|
||||
}
|
||||
Bool SamplerState::ValidateName(Uint index) const {
|
||||
return m_indexGenerator.IsValid(index);
|
||||
}
|
||||
|
||||
Bool SamplerState::ValidateSamplerObject(Uint index) const {
|
||||
return m_samplerObjects.find(index) != m_samplerObjects.end();
|
||||
}
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
Bool SamplerState::ValidateSamplerObject(Uint index) const {
|
||||
return m_samplerObjects.find(index) != m_samplerObjects.end();
|
||||
}
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -18,9 +18,9 @@ namespace MobileGL {
|
||||
public:
|
||||
SamplerState();
|
||||
|
||||
Vector<Uint> GenerateNames(Uint number);
|
||||
SharedPtr<SamplerObject> GetSamplerObject(Uint index);
|
||||
SharedPtr<SamplerObject> CreateSamplerObject(Uint index);
|
||||
void GenerateNames(Uint number, Vector<Uint>& samplers);
|
||||
const SharedPtr<SamplerObject>& GetSamplerObject(Uint index);
|
||||
const SharedPtr<SamplerObject>& CreateSamplerObject(Uint index);
|
||||
void MarkSamplerObjectForDeletion(Uint index);
|
||||
Bool ValidateName(Uint index) const;
|
||||
Bool ValidateSamplerObject(Uint index) const;
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace MobileGL {
|
||||
return {0, 0, 0};
|
||||
}
|
||||
|
||||
SharedPtr<SamplerObject> TextureObjectBase::GetSamplerObject() const {
|
||||
const SharedPtr<SamplerObject>& TextureObjectBase::GetSamplerObject() const {
|
||||
return m_sampler;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,113 +14,107 @@
|
||||
#include <Includes.h>
|
||||
#include <MG_Util/Math/VectorTypes.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
namespace GLState {
|
||||
class ITextureObject {
|
||||
public:
|
||||
using TargetEnum = TextureTarget;
|
||||
virtual ~ITextureObject() = default;
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
class ITextureObject {
|
||||
public:
|
||||
using TargetEnum = TextureTarget;
|
||||
virtual ~ITextureObject() = default;
|
||||
|
||||
virtual TextureStorageType GetStorageType() const = 0;
|
||||
virtual TextureStorageType GetStorageType() const = 0;
|
||||
|
||||
virtual TextureInternalFormat GetFormat() const = 0;
|
||||
virtual TextureTarget GetTarget() const = 0;
|
||||
virtual const Vector<TextureUploadTarget>& GetUploadTargets() const = 0;
|
||||
virtual IntVec3 GetBaseSize() const = 0;
|
||||
virtual SharedPtr<SamplerObject> GetSamplerObject() const = 0;
|
||||
virtual void SetInternalFormat(TextureInternalFormat format) = 0;
|
||||
virtual Bool IsComplete() const = 0;
|
||||
virtual Uint GetExternalIndex() const = 0;
|
||||
virtual const FloatVec4& GetBorderColor() const = 0;
|
||||
virtual void SetBorderColor(const FloatVec4& color) = 0;
|
||||
virtual TextureSwizzleParam GetSwizzleParam(TextureSwizzleParam param) const = 0;
|
||||
virtual void SetSwizzleParam(TextureSwizzleParam param, TextureSwizzleParam value) = 0;
|
||||
virtual void SetSwizzleParamRGBA(const Vec4<TextureSwizzleParam>& values) = 0;
|
||||
virtual const Vec4<TextureSwizzleParam>& GetAllSwizzleParams() const = 0;
|
||||
virtual const UintVec2& GetLevelRange() const = 0;
|
||||
virtual void SetBaseLevel(Uint baseLevel) = 0;
|
||||
virtual void SetMaxLevel(Uint maxLevel) = 0;
|
||||
virtual Uint16 GetTextureParamsVersion() const = 0;
|
||||
virtual TextureInternalFormat GetFormat() const = 0;
|
||||
virtual TextureTarget GetTarget() const = 0;
|
||||
virtual const Vector<TextureUploadTarget>& GetUploadTargets() const = 0;
|
||||
virtual IntVec3 GetBaseSize() const = 0;
|
||||
virtual const SharedPtr<SamplerObject>& GetSamplerObject() const = 0;
|
||||
virtual void SetInternalFormat(TextureInternalFormat format) = 0;
|
||||
virtual Bool IsComplete() const = 0;
|
||||
virtual Uint GetExternalIndex() const = 0;
|
||||
virtual const FloatVec4& GetBorderColor() const = 0;
|
||||
virtual void SetBorderColor(const FloatVec4& color) = 0;
|
||||
virtual TextureSwizzleParam GetSwizzleParam(TextureSwizzleParam param) const = 0;
|
||||
virtual void SetSwizzleParam(TextureSwizzleParam param, TextureSwizzleParam value) = 0;
|
||||
virtual void SetSwizzleParamRGBA(const Vec4<TextureSwizzleParam>& values) = 0;
|
||||
virtual const Vec4<TextureSwizzleParam>& GetAllSwizzleParams() const = 0;
|
||||
virtual const UintVec2& GetLevelRange() const = 0;
|
||||
virtual void SetBaseLevel(Uint baseLevel) = 0;
|
||||
virtual void SetMaxLevel(Uint maxLevel) = 0;
|
||||
virtual Uint16 GetTextureParamsVersion() const = 0;
|
||||
|
||||
protected:
|
||||
virtual Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const = 0;
|
||||
};
|
||||
protected:
|
||||
virtual Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const = 0;
|
||||
};
|
||||
|
||||
class TextureObjectBase : public ITextureObject {
|
||||
public:
|
||||
TextureObjectBase(TextureTarget target, Uint externalIndex);
|
||||
virtual ~TextureObjectBase() = default;
|
||||
class TextureObjectBase : public ITextureObject {
|
||||
public:
|
||||
TextureObjectBase(TextureTarget target, Uint externalIndex);
|
||||
virtual ~TextureObjectBase() = default;
|
||||
|
||||
TextureInternalFormat GetFormat() const override;
|
||||
TextureTarget GetTarget() const override;
|
||||
IntVec3 GetBaseSize() const override;
|
||||
SharedPtr<SamplerObject> GetSamplerObject() const override;
|
||||
void SetInternalFormat(TextureInternalFormat format) override;
|
||||
Bool IsComplete() const override;
|
||||
Uint GetExternalIndex() const override;
|
||||
const FloatVec4& GetBorderColor() const override;
|
||||
void SetBorderColor(const FloatVec4& color) override;
|
||||
TextureSwizzleParam GetSwizzleParam(TextureSwizzleParam param) const override;
|
||||
const Vec4<TextureSwizzleParam>& GetAllSwizzleParams() const override;
|
||||
void SetSwizzleParam(TextureSwizzleParam param, TextureSwizzleParam value) override;
|
||||
void SetSwizzleParamRGBA(const Vec4<TextureSwizzleParam>& values) override;
|
||||
const UintVec2& GetLevelRange() const override;
|
||||
void SetBaseLevel(Uint baseLevel) override;
|
||||
void SetMaxLevel(Uint maxLevel) override;
|
||||
Uint16 GetTextureParamsVersion() const override;
|
||||
TextureInternalFormat GetFormat() const override;
|
||||
TextureTarget GetTarget() const override;
|
||||
IntVec3 GetBaseSize() const override;
|
||||
const SharedPtr<SamplerObject>& GetSamplerObject() const override;
|
||||
void SetInternalFormat(TextureInternalFormat format) override;
|
||||
Bool IsComplete() const override;
|
||||
Uint GetExternalIndex() const override;
|
||||
const FloatVec4& GetBorderColor() const override;
|
||||
void SetBorderColor(const FloatVec4& color) override;
|
||||
TextureSwizzleParam GetSwizzleParam(TextureSwizzleParam param) const override;
|
||||
const Vec4<TextureSwizzleParam>& GetAllSwizzleParams() const override;
|
||||
void SetSwizzleParam(TextureSwizzleParam param, TextureSwizzleParam value) override;
|
||||
void SetSwizzleParamRGBA(const Vec4<TextureSwizzleParam>& values) override;
|
||||
const UintVec2& GetLevelRange() const override;
|
||||
void SetBaseLevel(Uint baseLevel) override;
|
||||
void SetMaxLevel(Uint maxLevel) override;
|
||||
Uint16 GetTextureParamsVersion() const override;
|
||||
|
||||
protected:
|
||||
const Uint m_externalIndex;
|
||||
const TextureTarget m_target = TextureTarget::Unknown;
|
||||
TextureInternalFormat m_internalFormat = TextureInternalFormat::Unknown;
|
||||
SharedPtr<SamplerObject> m_sampler = nullptr;
|
||||
FloatVec4 m_borderColor = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
Vec4<TextureSwizzleParam> m_swizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green,
|
||||
TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha};
|
||||
UintVec2 m_levelRange = {0, 1000};
|
||||
Uint16 m_textureParamsVersion = 0;
|
||||
};
|
||||
protected:
|
||||
const Uint m_externalIndex;
|
||||
const TextureTarget m_target = TextureTarget::Unknown;
|
||||
TextureInternalFormat m_internalFormat = TextureInternalFormat::Unknown;
|
||||
SharedPtr<SamplerObject> m_sampler = nullptr;
|
||||
FloatVec4 m_borderColor = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
Vec4<TextureSwizzleParam> m_swizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green,
|
||||
TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha};
|
||||
UintVec2 m_levelRange = {0, 1000};
|
||||
Uint16 m_textureParamsVersion = 0;
|
||||
};
|
||||
|
||||
class TextureObjectMipmap : public TextureObjectBase {
|
||||
public:
|
||||
TextureObjectMipmap(TextureTarget target, Uint externalIndex)
|
||||
: TextureObjectBase(target, externalIndex) {}
|
||||
class TextureObjectMipmap : public TextureObjectBase {
|
||||
public:
|
||||
TextureObjectMipmap(TextureTarget target, Uint externalIndex) : TextureObjectBase(target, externalIndex) {}
|
||||
|
||||
TextureStorageType GetStorageType() const override { return TextureStorageType::Mipmap; }
|
||||
TextureStorageType GetStorageType() const override { return TextureStorageType::Mipmap; }
|
||||
|
||||
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 = true) = 0;
|
||||
virtual Bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const = 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 = true) = 0;
|
||||
virtual Bool IsStorageDirty(TextureUploadTarget uploadTarget, Uint mipmapLevel) const = 0;
|
||||
};
|
||||
|
||||
class TextureObjectWithOneMipmap : public TextureObjectMipmap {
|
||||
public:
|
||||
TextureObjectWithOneMipmap(TextureTarget target, Uint externalIndex)
|
||||
: TextureObjectMipmap(target, externalIndex) {}
|
||||
virtual ~TextureObjectWithOneMipmap() = default;
|
||||
class TextureObjectWithOneMipmap : public TextureObjectMipmap {
|
||||
public:
|
||||
TextureObjectWithOneMipmap(TextureTarget target, Uint externalIndex)
|
||||
: TextureObjectMipmap(target, externalIndex) {}
|
||||
virtual ~TextureObjectWithOneMipmap() = default;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
IntVec3 GetBaseSize() const override;
|
||||
Bool IsComplete() const override;
|
||||
IntVec3 GetBaseSize() const override;
|
||||
Bool IsComplete() const override;
|
||||
|
||||
protected:
|
||||
MipmapUploadTargetArray<1> m_textureStorage;
|
||||
};
|
||||
} // namespace GLState
|
||||
} // namespace MG_State
|
||||
} // namespace MobileGL
|
||||
protected:
|
||||
MipmapUploadTargetArray<1> m_textureStorage;
|
||||
};
|
||||
} // namespace MobileGL::MG_State::GLState
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "TextureObject.h"
|
||||
#include "MG_State/GLState/BufferState/BufferObject.h"
|
||||
#include <MG_State/GLState/BufferState/BufferObject.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user