mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 22:28:32 +09:00
[Fix] (MG_Backend/DirectGLES): fix Photon image replay
This commit is contained in:
@@ -325,7 +325,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
namespace TextureImpl {
|
namespace TextureImpl {
|
||||||
SharedPtr<BackendTextureObject>& SyncTextureObjectToBackend(
|
SharedPtr<BackendTextureObject>& SyncTextureObjectToBackend(
|
||||||
const SharedPtr<MG_State::GLState::ITextureObject>& textureObject) {
|
const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
|
||||||
|
Bool imageBindableStorageRequired) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
#endif
|
#endif
|
||||||
@@ -335,6 +336,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
if (!exist) {
|
if (!exist) {
|
||||||
backendObj = MakeShared<BackendTextureObject>();
|
backendObj = MakeShared<BackendTextureObject>();
|
||||||
}
|
}
|
||||||
|
if (imageBindableStorageRequired) {
|
||||||
|
backendObj->RequireImageBindableStorage();
|
||||||
|
}
|
||||||
backendObj->SyncTextureParamsToBackend(textureObject);
|
backendObj->SyncTextureParamsToBackend(textureObject);
|
||||||
backendObj->SyncBuiltinSamplerToBackend(textureObject);
|
backendObj->SyncBuiltinSamplerToBackend(textureObject);
|
||||||
backendObj->SyncMipmapsToBackend(textureObject);
|
backendObj->SyncMipmapsToBackend(textureObject);
|
||||||
@@ -376,6 +380,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Bool SupportsLayeredImageBinding(TextureTarget target) {
|
||||||
|
return target == TextureTarget::Texture3D || target == TextureTarget::TextureCubeMap ||
|
||||||
|
target == TextureTarget::Texture2DArray || target == TextureTarget::TextureCubeMapArray ||
|
||||||
|
target == TextureTarget::Texture2DMultisampleArray;
|
||||||
|
}
|
||||||
|
|
||||||
void SyncImageTextureBinding(Uint unit) {
|
void SyncImageTextureBinding(Uint unit) {
|
||||||
#ifdef TRACY_ENABLE
|
#ifdef TRACY_ENABLE
|
||||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||||
@@ -386,10 +396,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& backendTexture = SyncTextureObjectToBackend(imageBinding.Texture);
|
auto& backendTexture = SyncTextureObjectToBackend(imageBinding.Texture, true);
|
||||||
|
const GLboolean layered =
|
||||||
|
SupportsLayeredImageBinding(imageBinding.Texture->GetTarget()) ? imageBinding.Layered : GL_FALSE;
|
||||||
g_GLESFuncs.glBindImageTexture(unit, backendTexture->GetBackendTextureId(), imageBinding.Level,
|
g_GLESFuncs.glBindImageTexture(unit, backendTexture->GetBackendTextureId(), imageBinding.Level,
|
||||||
imageBinding.Layered, imageBinding.Layer, imageBinding.Access,
|
layered, imageBinding.Layer, imageBinding.Access, imageBinding.Format);
|
||||||
imageBinding.Format);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SyncImageTextureBindings() {
|
void SyncImageTextureBindings() {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
|
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectGLES {
|
namespace MobileGL::MG_Backend::DirectGLES {
|
||||||
constexpr Bool PREFER_MAP_BUFFER_RANGE_FOR_BUFFER_SYNC = false;
|
constexpr Bool PREFER_MAP_BUFFER_RANGE_FOR_BUFFER_SYNC = false;
|
||||||
@@ -59,6 +60,46 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String PackPhotonSharedVec3Memory(String source) {
|
||||||
|
constexpr const char* declaration = "shared vec3 shared_memory[256][9];";
|
||||||
|
const SizeT declarationPos = source.find(declaration);
|
||||||
|
if (declarationPos == String::npos) {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
source.replace(declarationPos, String(declaration).size(),
|
||||||
|
"shared float shared_memory[256][9][3];\n"
|
||||||
|
"void StorePhotonSharedMemory(uint row, uint column, vec3 value)\n"
|
||||||
|
"{\n"
|
||||||
|
" shared_memory[row][column][0] = value.x;\n"
|
||||||
|
" shared_memory[row][column][1] = value.y;\n"
|
||||||
|
" shared_memory[row][column][2] = value.z;\n"
|
||||||
|
"}\n"
|
||||||
|
"vec3 LoadPhotonSharedMemory(uint row, uint column)\n"
|
||||||
|
"{\n"
|
||||||
|
" return vec3(shared_memory[row][column][0], shared_memory[row][column][1], "
|
||||||
|
"shared_memory[row][column][2]);\n"
|
||||||
|
"}\n");
|
||||||
|
|
||||||
|
source = std::regex_replace(
|
||||||
|
source, std::regex(R"(shared_memory\[([^\]]+)\]\[([^\]]+)\] \+= ([^;]+);)"),
|
||||||
|
"StorePhotonSharedMemory($1, $2, LoadPhotonSharedMemory($1, $2) + ($3));");
|
||||||
|
source = std::regex_replace(
|
||||||
|
source, std::regex(R"(shared_memory\[([^\]]+)\]\[([^\]]+)\] = ([^;]+);)"),
|
||||||
|
"StorePhotonSharedMemory($1, $2, $3);");
|
||||||
|
source = std::regex_replace(source, std::regex(R"(shared_memory\[([^\]]+)\]\[([^\]]+)\](?!\[))"),
|
||||||
|
"LoadPhotonSharedMemory($1, $2)");
|
||||||
|
source = std::regex_replace(source, std::regex(R"(LoadPhotonSharedMemory\(0,)"),
|
||||||
|
"LoadPhotonSharedMemory(0u,");
|
||||||
|
source = std::regex_replace(source, std::regex(R"(vec3 ([A-Za-z_][A-Za-z0-9_]*)\[9\] = shared_memory\[0\];)"),
|
||||||
|
"vec3 $1[9];\n"
|
||||||
|
" for (uint photon_band = 0u; photon_band < 9u; ++photon_band)\n"
|
||||||
|
" {\n"
|
||||||
|
" $1[photon_band] = LoadPhotonSharedMemory(0u, photon_band);\n"
|
||||||
|
" }");
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
String InjectUniformAfterVersion(String source, const String& declaration) {
|
String InjectUniformAfterVersion(String source, const String& declaration) {
|
||||||
const SizeT versionPos = source.find("#version");
|
const SizeT versionPos = source.find("#version");
|
||||||
if (versionPos == String::npos) {
|
if (versionPos == String::npos) {
|
||||||
@@ -498,6 +539,38 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return m_backendTextureId;
|
return m_backendTextureId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BackendTextureObject::RequireImageBindableStorage() {
|
||||||
|
if (m_imageBindableStorageRequired) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_imageBindableStorageRequired = true;
|
||||||
|
m_isInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackendTextureObject::RecreateBackendTexture() {
|
||||||
|
if (m_backendTextureId != 0) {
|
||||||
|
g_GLESFuncs.glDeleteTextures(1, &m_backendTextureId);
|
||||||
|
for (auto& unitCache : g_boundTexturesCache) {
|
||||||
|
for (auto& boundTexture : unitCache) {
|
||||||
|
if (boundTexture == this) {
|
||||||
|
boundTexture = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_GLESFuncs.glGenTextures(1, &m_backendTextureId);
|
||||||
|
if (m_backendTextureId == 0) {
|
||||||
|
MGLOG_E("Failed to regenerate texture object.");
|
||||||
|
MGLOG_E("ES glGetError(): %s", MG_Util::ConvertGLEnumToString(g_GLESFuncs.glGetError()).c_str());
|
||||||
|
} else {
|
||||||
|
MGLOG_D("Regenerated texture object with ID: %u.", m_backendTextureId);
|
||||||
|
}
|
||||||
|
m_isInitialized = false;
|
||||||
|
m_backendStorageImmutable = false;
|
||||||
|
m_prevTextureInfo = {};
|
||||||
|
}
|
||||||
|
|
||||||
class ScopedDefaultUnpackState {
|
class ScopedDefaultUnpackState {
|
||||||
public:
|
public:
|
||||||
ScopedDefaultUnpackState() {
|
ScopedDefaultUnpackState() {
|
||||||
@@ -686,8 +759,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
currentTextureInfo.mipmapLevels = mipmapCount;
|
currentTextureInfo.mipmapLevels = mipmapCount;
|
||||||
|
|
||||||
Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo);
|
Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo);
|
||||||
|
if (needsRegeneration && m_backendStorageImmutable) {
|
||||||
|
RecreateBackendTexture();
|
||||||
|
Bind(target);
|
||||||
|
}
|
||||||
|
|
||||||
const Bool canAppendMipmaps =
|
const Bool canAppendMipmaps =
|
||||||
m_isInitialized &&
|
m_isInitialized &&
|
||||||
|
!m_imageBindableStorageRequired &&
|
||||||
|
!stateTextureObject->IsImmutable() &&
|
||||||
currentTextureInfo.internalFormat == m_prevTextureInfo.internalFormat &&
|
currentTextureInfo.internalFormat == m_prevTextureInfo.internalFormat &&
|
||||||
currentTextureInfo.width == m_prevTextureInfo.width &&
|
currentTextureInfo.width == m_prevTextureInfo.width &&
|
||||||
currentTextureInfo.height == m_prevTextureInfo.height &&
|
currentTextureInfo.height == m_prevTextureInfo.height &&
|
||||||
@@ -795,12 +875,93 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
MOBILEGL_ASSERT(false, "Unexpected multisample target: %d", static_cast<Int>(targetInternal));
|
MOBILEGL_ASSERT(false, "Unexpected multisample target: %d", static_cast<Int>(targetInternal));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
m_backendStorageImmutable = true;
|
||||||
for (const auto& uploadTarget : uploadTargets) {
|
for (const auto& uploadTarget : uploadTargets) {
|
||||||
for (SizeT level = 0; level < mipmapCount; ++level) {
|
for (SizeT level = 0; level < mipmapCount; ++level) {
|
||||||
textureMipmapObject->MarkStorageDirty(uploadTarget, level, false);
|
textureMipmapObject->MarkStorageDirty(uploadTarget, level, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (stateTextureObject->IsImmutable() || m_imageBindableStorageRequired) {
|
||||||
|
DebugImpl::ErrorLopper::Clear();
|
||||||
|
g_GLESFuncs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
switch (targetInternal) {
|
||||||
|
case TextureTarget::Texture2D:
|
||||||
|
case TextureTarget::TextureCubeMap:
|
||||||
|
g_GLESFuncs.glTexStorage2D(target, static_cast<GLsizei>(mipmapCount), glInternalFormat,
|
||||||
|
static_cast<GLsizei>(baseSize.x()),
|
||||||
|
static_cast<GLsizei>(baseSize.y()));
|
||||||
|
break;
|
||||||
|
case TextureTarget::Texture3D:
|
||||||
|
g_GLESFuncs.glTexStorage3D(target, static_cast<GLsizei>(mipmapCount), glInternalFormat,
|
||||||
|
static_cast<GLsizei>(baseSize.x()),
|
||||||
|
static_cast<GLsizei>(baseSize.y()),
|
||||||
|
static_cast<GLsizei>(baseSize.z()));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MGLOG_E("Unhandled immutable texture target %s",
|
||||||
|
MG_Util::ConvertTextureTargetToString(targetInternal).c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__, target,
|
||||||
|
glInternalFormat](GLenum err) {
|
||||||
|
MGLOG_D("%s(%s:%d) ES error: %s. glTexStorage*: target=%s, internalformat=%s", func,
|
||||||
|
file, line, MG_Util::ConvertGLEnumToString(err).c_str(),
|
||||||
|
MG_Util::ConvertGLEnumToString(target).c_str(),
|
||||||
|
MG_Util::ConvertGLEnumToString(glInternalFormat).c_str());
|
||||||
|
});
|
||||||
|
m_backendStorageImmutable = true;
|
||||||
|
|
||||||
|
ScopedDefaultUnpackState unpackState;
|
||||||
|
for (auto& uploadTarget : uploadTargets) {
|
||||||
|
for (SizeT level = 0; level < mipmapCount; ++level) {
|
||||||
|
auto levelByteSize = textureMipmapObject->GetMipmapByteSize(uploadTarget, level);
|
||||||
|
const bool levelDirty = textureMipmapObject->IsStorageDirty(uploadTarget, level);
|
||||||
|
if (levelDirty && levelByteSize != 0) {
|
||||||
|
auto levelTexelSize =
|
||||||
|
textureMipmapObject->GetMipmapTexelSize(uploadTarget, level);
|
||||||
|
auto glUploadTarget = MG_Util::ConvertTextureUploadTargetToGLEnum(uploadTarget);
|
||||||
|
auto* pData = textureMipmapObject->MapMipmapData(uploadTarget, level);
|
||||||
|
Vector<Float> convertedUploadData;
|
||||||
|
const void* uploadData = PrepareNormFloatFallbackUpload(
|
||||||
|
textureMipmapObject->GetFormat(), levelTexelSize, pData, levelByteSize, glType,
|
||||||
|
convertedUploadData);
|
||||||
|
|
||||||
|
DebugImpl::ErrorLopper::Clear();
|
||||||
|
g_GLESFuncs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
switch (targetInternal) {
|
||||||
|
case TextureTarget::Texture2D:
|
||||||
|
case TextureTarget::TextureCubeMap:
|
||||||
|
g_GLESFuncs.glTexSubImage2D(
|
||||||
|
glUploadTarget, static_cast<GLint>(level), 0, 0,
|
||||||
|
static_cast<GLsizei>(levelTexelSize.x()),
|
||||||
|
static_cast<GLsizei>(levelTexelSize.y()), glFormat, glType, uploadData);
|
||||||
|
break;
|
||||||
|
case TextureTarget::Texture3D:
|
||||||
|
g_GLESFuncs.glTexSubImage3D(
|
||||||
|
glUploadTarget, static_cast<GLint>(level), 0, 0, 0,
|
||||||
|
static_cast<GLsizei>(levelTexelSize.x()),
|
||||||
|
static_cast<GLsizei>(levelTexelSize.y()),
|
||||||
|
static_cast<GLsizei>(levelTexelSize.z()), glFormat, glType, uploadData);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DebugImpl::ErrorLopper::Loop(
|
||||||
|
[file = __FILE__, line = __LINE__, func = __func__, glUploadTarget,
|
||||||
|
glFormat, glType, pData](GLenum err) {
|
||||||
|
MGLOG_D("%s(%s:%d) ES error: %s. glTexSubImage*: target=%s, format=%s, "
|
||||||
|
"type=%s, pixels=%p",
|
||||||
|
func, file, line, MG_Util::ConvertGLEnumToString(err).c_str(),
|
||||||
|
MG_Util::ConvertGLEnumToString(glUploadTarget).c_str(),
|
||||||
|
MG_Util::ConvertGLEnumToString(glFormat).c_str(),
|
||||||
|
MG_Util::ConvertGLEnumToString(glType).c_str(), pData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
textureMipmapObject->MarkStorageDirty(uploadTarget, level, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
m_backendStorageImmutable = false;
|
||||||
ScopedDefaultUnpackState unpackState;
|
ScopedDefaultUnpackState unpackState;
|
||||||
for (auto& uploadTarget : uploadTargets) {
|
for (auto& uploadTarget : uploadTargets) {
|
||||||
for (SizeT level = 0; level < mipmapCount; ++level) {
|
for (SizeT level = 0; level < mipmapCount; ++level) {
|
||||||
@@ -1690,6 +1851,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
source = ClampNormFallbackOutputs(std::move(source), glShaderType,
|
source = ClampNormFallbackOutputs(std::move(source), glShaderType,
|
||||||
m_snormFallbackClampOutputMask,
|
m_snormFallbackClampOutputMask,
|
||||||
m_unormFallbackClampOutputMask);
|
m_unormFallbackClampOutputMask);
|
||||||
|
source = PackPhotonSharedVec3Memory(std::move(source));
|
||||||
|
|
||||||
// Patch for Photon compiler precision issue
|
// Patch for Photon compiler precision issue
|
||||||
String findStr = "1000000.0";
|
String findStr = "1000000.0";
|
||||||
|
|||||||
@@ -205,12 +205,17 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
void SyncMipmapsToBackend(const 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 SyncBuiltinSamplerToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||||
void SyncTextureParamsToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
void SyncTextureParamsToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||||
|
void RequireImageBindableStorage();
|
||||||
void Bind(GLenum target, Uint unit = TempTextureUnit);
|
void Bind(GLenum target, Uint unit = TempTextureUnit);
|
||||||
Uint GetBackendTextureId() const;
|
Uint GetBackendTextureId() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void RecreateBackendTexture();
|
||||||
|
|
||||||
Uint m_backendTextureId = 0;
|
Uint m_backendTextureId = 0;
|
||||||
Bool m_isInitialized = false;
|
Bool m_isInitialized = false;
|
||||||
|
Bool m_imageBindableStorageRequired = false;
|
||||||
|
Bool m_backendStorageImmutable = false;
|
||||||
StateTextureBasicInfo m_prevTextureInfo;
|
StateTextureBasicInfo m_prevTextureInfo;
|
||||||
SamplerParameters m_cacheSamplerParameters;
|
SamplerParameters m_cacheSamplerParameters;
|
||||||
UintVec2 m_cacheLodRange = {0, 1000};
|
UintVec2 m_cacheLodRange = {0, 1000};
|
||||||
@@ -226,7 +231,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
extern StateBackendObjectRegistry<MG_State::GLState::ITextureObject, BackendTextureObject>
|
extern StateBackendObjectRegistry<MG_State::GLState::ITextureObject, BackendTextureObject>
|
||||||
g_backendTextureObjects;
|
g_backendTextureObjects;
|
||||||
SharedPtr<BackendTextureObject>& SyncTextureObjectToBackend(
|
SharedPtr<BackendTextureObject>& SyncTextureObjectToBackend(
|
||||||
const SharedPtr<MG_State::GLState::ITextureObject>& textureObject);
|
const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
|
||||||
|
Bool imageBindableStorageRequired = false);
|
||||||
extern Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>,
|
extern Array<Array<BackendTextureObject*, (SizeT)TextureTarget::TextureTargetCount>,
|
||||||
MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
|
MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS>
|
||||||
g_boundTexturesCache;
|
g_boundTexturesCache;
|
||||||
|
|||||||
Reference in New Issue
Block a user