mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 14:18:31 +09:00
[Feat] (MG_Backend, android-plugin): show format capability tables in POST
This commit is contained in:
@@ -15,23 +15,6 @@
|
|||||||
|
|
||||||
namespace MobileGL::MG_Backend {
|
namespace MobileGL::MG_Backend {
|
||||||
namespace {
|
namespace {
|
||||||
constexpr FormatCapability kPrintedFormatCapabilities[] = {
|
|
||||||
FormatCapability::Creatable,
|
|
||||||
FormatCapability::Sampled,
|
|
||||||
FormatCapability::LinearFilter,
|
|
||||||
FormatCapability::GenerateMipmap,
|
|
||||||
FormatCapability::TextureGather,
|
|
||||||
FormatCapability::TextureShadow,
|
|
||||||
FormatCapability::FramebufferRenderable,
|
|
||||||
FormatCapability::FramebufferLayered,
|
|
||||||
FormatCapability::MultisampleTexture,
|
|
||||||
FormatCapability::MultisampleRenderbuffer,
|
|
||||||
FormatCapability::ColorAttachment,
|
|
||||||
FormatCapability::DepthAttachment,
|
|
||||||
FormatCapability::StencilAttachment,
|
|
||||||
FormatCapability::TextureBuffer,
|
|
||||||
};
|
|
||||||
|
|
||||||
Bool IsReleaseCurrentRequest(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
Bool IsReleaseCurrentRequest(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
|
||||||
(void)dpy;
|
(void)dpy;
|
||||||
return draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE && ctx == EGL_NO_CONTEXT;
|
return draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE && ctx == EGL_NO_CONTEXT;
|
||||||
@@ -41,40 +24,6 @@ namespace MobileGL::MG_Backend {
|
|||||||
return std::this_thread::get_id();
|
return std::this_thread::get_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* ConvertFormatCapabilityToString(FormatCapability capability) {
|
|
||||||
switch (capability) {
|
|
||||||
case FormatCapability::Creatable:
|
|
||||||
return "Creatable";
|
|
||||||
case FormatCapability::Sampled:
|
|
||||||
return "Sampled";
|
|
||||||
case FormatCapability::LinearFilter:
|
|
||||||
return "LinearFilter";
|
|
||||||
case FormatCapability::GenerateMipmap:
|
|
||||||
return "GenerateMipmap";
|
|
||||||
case FormatCapability::TextureGather:
|
|
||||||
return "TextureGather";
|
|
||||||
case FormatCapability::TextureShadow:
|
|
||||||
return "TextureShadow";
|
|
||||||
case FormatCapability::FramebufferRenderable:
|
|
||||||
return "FramebufferRenderable";
|
|
||||||
case FormatCapability::FramebufferLayered:
|
|
||||||
return "FramebufferLayered";
|
|
||||||
case FormatCapability::MultisampleTexture:
|
|
||||||
return "MultisampleTexture";
|
|
||||||
case FormatCapability::MultisampleRenderbuffer:
|
|
||||||
return "MultisampleRenderbuffer";
|
|
||||||
case FormatCapability::ColorAttachment:
|
|
||||||
return "ColorAttachment";
|
|
||||||
case FormatCapability::DepthAttachment:
|
|
||||||
return "DepthAttachment";
|
|
||||||
case FormatCapability::StencilAttachment:
|
|
||||||
return "StencilAttachment";
|
|
||||||
case FormatCapability::TextureBuffer:
|
|
||||||
return "TextureBuffer";
|
|
||||||
}
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* GetFormatCapabilitySupportString(const FormatCapabilityCache& cache,
|
const char* GetFormatCapabilitySupportString(const FormatCapabilityCache& cache,
|
||||||
SizeT targetIndex,
|
SizeT targetIndex,
|
||||||
SizeT formatIndex,
|
SizeT formatIndex,
|
||||||
@@ -94,22 +43,17 @@ namespace MobileGL::MG_Backend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SizeT GetCapabilityColumnWidth(FormatCapability capability) {
|
SizeT GetCapabilityColumnWidth(FormatCapability capability) {
|
||||||
SizeT width = std::strlen(ConvertFormatCapabilityToString(capability));
|
SizeT width = std::strlen(GetFormatCapabilityName(capability));
|
||||||
width = std::max<SizeT>(width, std::strlen("Caveat"));
|
width = std::max<SizeT>(width, std::strlen("Caveat"));
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
String GetFormatCapabilityTargetName(SizeT targetIndex) {
|
|
||||||
if (targetIndex == kFormatCapabilityRenderbufferTargetIndex) return "Renderbuffer";
|
|
||||||
return MG_Util::ConvertTextureTargetToString(static_cast<TextureTarget>(targetIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
String BuildFormatCapabilityHeader(SizeT formatNameWidth) {
|
String BuildFormatCapabilityHeader(SizeT formatNameWidth) {
|
||||||
std::ostringstream line;
|
std::ostringstream line;
|
||||||
line << std::left << std::setw(static_cast<Int>(formatNameWidth)) << "";
|
line << std::left << std::setw(static_cast<Int>(formatNameWidth)) << "";
|
||||||
for (FormatCapability capability : kPrintedFormatCapabilities) {
|
for (FormatCapability capability : kReportedFormatCapabilities) {
|
||||||
line << " | " << std::left << std::setw(static_cast<Int>(GetCapabilityColumnWidth(capability)))
|
line << " | " << std::left << std::setw(static_cast<Int>(GetCapabilityColumnWidth(capability)))
|
||||||
<< ConvertFormatCapabilityToString(capability);
|
<< GetFormatCapabilityName(capability);
|
||||||
}
|
}
|
||||||
return line.str();
|
return line.str();
|
||||||
}
|
}
|
||||||
@@ -122,7 +66,7 @@ namespace MobileGL::MG_Backend {
|
|||||||
std::ostringstream line;
|
std::ostringstream line;
|
||||||
line << std::left << std::setw(static_cast<Int>(formatNameWidth))
|
line << std::left << std::setw(static_cast<Int>(formatNameWidth))
|
||||||
<< MG_Util::ConvertTextureInternalFormatToString(format);
|
<< MG_Util::ConvertTextureInternalFormatToString(format);
|
||||||
for (FormatCapability capability : kPrintedFormatCapabilities) {
|
for (FormatCapability capability : kReportedFormatCapabilities) {
|
||||||
line << " | " << std::left << std::setw(static_cast<Int>(GetCapabilityColumnWidth(capability)))
|
line << " | " << std::left << std::setw(static_cast<Int>(GetCapabilityColumnWidth(capability)))
|
||||||
<< GetFormatCapabilitySupportString(cache, targetIndex, formatIndex, capability);
|
<< GetFormatCapabilitySupportString(cache, targetIndex, formatIndex, capability);
|
||||||
}
|
}
|
||||||
@@ -160,6 +104,50 @@ namespace MobileGL::MG_Backend {
|
|||||||
return kFormatCapabilityRenderbufferTargetIndex;
|
return kFormatCapabilityRenderbufferTargetIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* GetFormatCapabilityName(FormatCapability capability) {
|
||||||
|
switch (capability) {
|
||||||
|
case FormatCapability::Creatable:
|
||||||
|
return "Creatable";
|
||||||
|
case FormatCapability::Sampled:
|
||||||
|
return "Sampled";
|
||||||
|
case FormatCapability::LinearFilter:
|
||||||
|
return "LinearFilter";
|
||||||
|
case FormatCapability::GenerateMipmap:
|
||||||
|
return "GenerateMipmap";
|
||||||
|
case FormatCapability::TextureGather:
|
||||||
|
return "TextureGather";
|
||||||
|
case FormatCapability::TextureShadow:
|
||||||
|
return "TextureShadow";
|
||||||
|
case FormatCapability::FramebufferRenderable:
|
||||||
|
return "FramebufferRenderable";
|
||||||
|
case FormatCapability::FramebufferLayered:
|
||||||
|
return "FramebufferLayered";
|
||||||
|
case FormatCapability::MultisampleTexture:
|
||||||
|
return "MultisampleTexture";
|
||||||
|
case FormatCapability::MultisampleRenderbuffer:
|
||||||
|
return "MultisampleRenderbuffer";
|
||||||
|
case FormatCapability::ColorAttachment:
|
||||||
|
return "ColorAttachment";
|
||||||
|
case FormatCapability::DepthAttachment:
|
||||||
|
return "DepthAttachment";
|
||||||
|
case FormatCapability::StencilAttachment:
|
||||||
|
return "StencilAttachment";
|
||||||
|
case FormatCapability::TextureBuffer:
|
||||||
|
return "TextureBuffer";
|
||||||
|
}
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
String GetFormatCapabilityTargetName(SizeT targetIndex) {
|
||||||
|
if (targetIndex == kFormatCapabilityRenderbufferTargetIndex) {
|
||||||
|
return "Renderbuffer";
|
||||||
|
}
|
||||||
|
if (targetIndex >= kFormatCapabilityTextureTargetCount) {
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
return MG_Util::ConvertTextureTargetToString(static_cast<TextureTarget>(targetIndex));
|
||||||
|
}
|
||||||
|
|
||||||
void PrintFormatCapabilities(const FormatCapabilityCache& cache) {
|
void PrintFormatCapabilities(const FormatCapabilityCache& cache) {
|
||||||
const SizeT formatNameWidth = GetPrintedFormatNameWidth();
|
const SizeT formatNameWidth = GetPrintedFormatNameWidth();
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,23 @@ namespace MobileGL {
|
|||||||
|
|
||||||
using FormatCapabilityFlags = Flags<FormatCapability>;
|
using FormatCapabilityFlags = Flags<FormatCapability>;
|
||||||
|
|
||||||
|
inline constexpr Array<FormatCapability, 14> kReportedFormatCapabilities = {
|
||||||
|
FormatCapability::Creatable,
|
||||||
|
FormatCapability::Sampled,
|
||||||
|
FormatCapability::LinearFilter,
|
||||||
|
FormatCapability::GenerateMipmap,
|
||||||
|
FormatCapability::TextureGather,
|
||||||
|
FormatCapability::TextureShadow,
|
||||||
|
FormatCapability::FramebufferRenderable,
|
||||||
|
FormatCapability::FramebufferLayered,
|
||||||
|
FormatCapability::MultisampleTexture,
|
||||||
|
FormatCapability::MultisampleRenderbuffer,
|
||||||
|
FormatCapability::ColorAttachment,
|
||||||
|
FormatCapability::DepthAttachment,
|
||||||
|
FormatCapability::StencilAttachment,
|
||||||
|
FormatCapability::TextureBuffer,
|
||||||
|
};
|
||||||
|
|
||||||
inline constexpr SizeT kFormatCapabilityTextureTargetCount =
|
inline constexpr SizeT kFormatCapabilityTextureTargetCount =
|
||||||
static_cast<SizeT>(TextureTarget::TextureTargetCount);
|
static_cast<SizeT>(TextureTarget::TextureTargetCount);
|
||||||
inline constexpr SizeT kFormatCapabilityRenderbufferTargetIndex = kFormatCapabilityTextureTargetCount;
|
inline constexpr SizeT kFormatCapabilityRenderbufferTargetIndex = kFormatCapabilityTextureTargetCount;
|
||||||
@@ -70,6 +87,8 @@ namespace MobileGL {
|
|||||||
Bool HasFormatCapability(FormatCapabilityFlags caps, FormatCapability capability);
|
Bool HasFormatCapability(FormatCapabilityFlags caps, FormatCapability capability);
|
||||||
SizeT GetFormatCapabilityTargetIndex(TextureTarget target);
|
SizeT GetFormatCapabilityTargetIndex(TextureTarget target);
|
||||||
SizeT GetRenderbufferFormatCapabilityTargetIndex();
|
SizeT GetRenderbufferFormatCapabilityTargetIndex();
|
||||||
|
const char* GetFormatCapabilityName(FormatCapability capability);
|
||||||
|
String GetFormatCapabilityTargetName(SizeT targetIndex);
|
||||||
void PrintFormatCapabilities(const FormatCapabilityCache& cache);
|
void PrintFormatCapabilities(const FormatCapabilityCache& cache);
|
||||||
|
|
||||||
// Opaque backend fence-sync handle, created by GLFunctionsTable::FenceSync
|
// Opaque backend fence-sync handle, created by GLFunctionsTable::FenceSync
|
||||||
|
|||||||
@@ -150,23 +150,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
String Reason;
|
String Reason;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr FormatCapability kGLESProbeCapabilities[] = {
|
|
||||||
FormatCapability::Creatable,
|
|
||||||
FormatCapability::Sampled,
|
|
||||||
FormatCapability::LinearFilter,
|
|
||||||
FormatCapability::GenerateMipmap,
|
|
||||||
FormatCapability::TextureGather,
|
|
||||||
FormatCapability::TextureShadow,
|
|
||||||
FormatCapability::FramebufferRenderable,
|
|
||||||
FormatCapability::FramebufferLayered,
|
|
||||||
FormatCapability::MultisampleTexture,
|
|
||||||
FormatCapability::MultisampleRenderbuffer,
|
|
||||||
FormatCapability::ColorAttachment,
|
|
||||||
FormatCapability::DepthAttachment,
|
|
||||||
FormatCapability::StencilAttachment,
|
|
||||||
FormatCapability::TextureBuffer,
|
|
||||||
};
|
|
||||||
|
|
||||||
GLESProbeFormatInfo BuildNativeProbeFormatInfo(GLenum requestedInternalFormat) {
|
GLESProbeFormatInfo BuildNativeProbeFormatInfo(GLenum requestedInternalFormat) {
|
||||||
GLESProbeFormatInfo info;
|
GLESProbeFormatInfo info;
|
||||||
info.InternalFormat = requestedInternalFormat;
|
info.InternalFormat = requestedInternalFormat;
|
||||||
@@ -176,9 +159,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
Flags<PixelFormatNormalizeOptionBit> GetForcedPixelFormatNormalizeOptions() {
|
Flags<PixelFormatNormalizeOptionBit> GetForcedPixelFormatNormalizeOptions(
|
||||||
|
const MG_External::GLESCapabilities& capabilities) {
|
||||||
Flags<PixelFormatNormalizeOptionBit> options;
|
Flags<PixelFormatNormalizeOptionBit> options;
|
||||||
if (g_GLESCapabilities.IsAngleRenderer) {
|
if (capabilities.IsAngleRenderer) {
|
||||||
options |= PixelFormatNormalizeOptionBit::NoRgb16;
|
options |= PixelFormatNormalizeOptionBit::NoRgb16;
|
||||||
options |= PixelFormatNormalizeOptionBit::NoSnorm16;
|
options |= PixelFormatNormalizeOptionBit::NoSnorm16;
|
||||||
options |= PixelFormatNormalizeOptionBit::NoSnorm8;
|
options |= PixelFormatNormalizeOptionBit::NoSnorm8;
|
||||||
@@ -186,11 +170,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
Flags<PixelFormatNormalizeOptionBit> GetDriverPixelFormatNormalizeOptions() {
|
Flags<PixelFormatNormalizeOptionBit> GetDriverPixelFormatNormalizeOptions(
|
||||||
|
const MG_External::GLESCapabilities& capabilities) {
|
||||||
Flags<PixelFormatNormalizeOptionBit> options = PixelFormatNormalizeOptionBit::NoDepthComponent32;
|
Flags<PixelFormatNormalizeOptionBit> options = PixelFormatNormalizeOptionBit::NoDepthComponent32;
|
||||||
options |= PixelFormatNormalizeOptionBit::NoRGBA8Snorm;
|
options |= PixelFormatNormalizeOptionBit::NoRGBA8Snorm;
|
||||||
options |= PixelFormatNormalizeOptionBit::NoRGB16Snorm;
|
options |= PixelFormatNormalizeOptionBit::NoRGB16Snorm;
|
||||||
if (!g_GLESCapabilities.SupportsNorm16Texture) {
|
if (!capabilities.SupportsNorm16Texture) {
|
||||||
options |= PixelFormatNormalizeOptionBit::NoNorm16;
|
options |= PixelFormatNormalizeOptionBit::NoNorm16;
|
||||||
}
|
}
|
||||||
return options;
|
return options;
|
||||||
@@ -241,21 +226,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return MG_Util::ConvertGLEnumToString(internalFormat);
|
return MG_Util::ConvertGLEnumToString(internalFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
String GetFormatCapabilityTargetNameForLog(SizeT targetIndex) {
|
|
||||||
if (targetIndex == GetRenderbufferFormatCapabilityTargetIndex()) {
|
|
||||||
return "Renderbuffer";
|
|
||||||
}
|
|
||||||
if (targetIndex < kFormatCapabilityTextureTargetCount) {
|
|
||||||
return MG_Util::ConvertTextureTargetToString(static_cast<TextureTarget>(targetIndex));
|
|
||||||
}
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogGLESFormatCaveat(TextureInternalFormat logicalFormat,
|
void LogGLESFormatCaveat(TextureInternalFormat logicalFormat,
|
||||||
SizeT targetIndex,
|
SizeT targetIndex,
|
||||||
const GLESProbeFormatInfo& fallbackInfo) {
|
const GLESProbeFormatInfo& fallbackInfo) {
|
||||||
MGLOG_D("Caveat: %s %s not fully supported. Reason: %s. Fallback: %s",
|
MGLOG_D("Caveat: %s %s not fully supported. Reason: %s. Fallback: %s",
|
||||||
GetFormatCapabilityTargetNameForLog(targetIndex).c_str(),
|
GetFormatCapabilityTargetName(targetIndex).c_str(),
|
||||||
MG_Util::ConvertTextureInternalFormatToString(logicalFormat).c_str(),
|
MG_Util::ConvertTextureInternalFormatToString(logicalFormat).c_str(),
|
||||||
fallbackInfo.Reason.c_str(),
|
fallbackInfo.Reason.c_str(),
|
||||||
ConvertFallbackInternalFormatToString(fallbackInfo.InternalFormat).c_str());
|
ConvertFallbackInternalFormatToString(fallbackInfo.InternalFormat).c_str());
|
||||||
@@ -306,7 +281,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
SizeT formatIndex,
|
SizeT formatIndex,
|
||||||
FormatCapabilityFlags caps) {
|
FormatCapabilityFlags caps) {
|
||||||
Bool added = false;
|
Bool added = false;
|
||||||
for (FormatCapability capability : kGLESProbeCapabilities) {
|
for (FormatCapability capability : kReportedFormatCapabilities) {
|
||||||
if (HasFormatCapability(caps, capability) &&
|
if (HasFormatCapability(caps, capability) &&
|
||||||
!HasFormatCapability(cache.FullCaps[targetIndex][formatIndex], capability)) {
|
!HasFormatCapability(cache.FullCaps[targetIndex][formatIndex], capability)) {
|
||||||
cache.CaveatCaps[targetIndex][formatIndex] |= capability;
|
cache.CaveatCaps[targetIndex][formatIndex] |= capability;
|
||||||
@@ -316,7 +291,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return added;
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
Int GetGLESFormatMaxSamples(const DynamicBackendParameters& dynamicParameters,
|
Int GetGLESFormatMaxSamples(const MG_External::GLESCapabilities& capabilities,
|
||||||
TextureInternalFormat logicalFormat,
|
TextureInternalFormat logicalFormat,
|
||||||
GLenum imageFormat) {
|
GLenum imageFormat) {
|
||||||
const Bool isDepth = MG_Util::IsDepthFormatInternalFormat(logicalFormat);
|
const Bool isDepth = MG_Util::IsDepthFormatInternalFormat(logicalFormat);
|
||||||
@@ -324,12 +299,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
const Bool isInteger = imageFormat == GL_RED_INTEGER || imageFormat == GL_RG_INTEGER ||
|
const Bool isInteger = imageFormat == GL_RED_INTEGER || imageFormat == GL_RG_INTEGER ||
|
||||||
imageFormat == GL_RGB_INTEGER || imageFormat == GL_RGBA_INTEGER;
|
imageFormat == GL_RGB_INTEGER || imageFormat == GL_RGBA_INTEGER;
|
||||||
if (isDepth || isStencil) {
|
if (isDepth || isStencil) {
|
||||||
return dynamicParameters.MaxDepthTextureSamples;
|
return capabilities.MaxDepthTextureSamples;
|
||||||
}
|
}
|
||||||
if (isInteger) {
|
if (isInteger) {
|
||||||
return dynamicParameters.MaxIntegerSamples;
|
return capabilities.MaxIntegerSamples;
|
||||||
}
|
}
|
||||||
return dynamicParameters.MaxColorTextureSamples;
|
return capabilities.MaxColorTextureSamples;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool ProbeFramebufferCompletenessForTexture(const MG_External::GLESFunctionsTable& gl,
|
Bool ProbeFramebufferCompletenessForTexture(const MG_External::GLESFunctionsTable& gl,
|
||||||
@@ -527,12 +502,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return sampleCounts;
|
return sampleCounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProbeGLESFormatCapabilities(const MG_External::GLESFunctionsTable& gl,
|
void PopulateFormatCapabilitiesImpl(const MG_External::GLESFunctionsTable& gl,
|
||||||
FormatCapabilityCache& cache,
|
const MG_External::GLESCapabilities& capabilities,
|
||||||
const DynamicBackendParameters& dynamicParameters) {
|
FormatCapabilityCache& cache) {
|
||||||
cache.Clear();
|
cache.Clear();
|
||||||
const Flags<PixelFormatNormalizeOptionBit> forcedOptions = GetForcedPixelFormatNormalizeOptions();
|
const Flags<PixelFormatNormalizeOptionBit> forcedOptions =
|
||||||
const Flags<PixelFormatNormalizeOptionBit> driverOptions = GetDriverPixelFormatNormalizeOptions();
|
GetForcedPixelFormatNormalizeOptions(capabilities);
|
||||||
|
const Flags<PixelFormatNormalizeOptionBit> driverOptions =
|
||||||
|
GetDriverPixelFormatNormalizeOptions(capabilities);
|
||||||
|
|
||||||
for (SizeT formatIndex = 0; formatIndex < kFormatCapabilityFormatCount; ++formatIndex) {
|
for (SizeT formatIndex = 0; formatIndex < kFormatCapabilityFormatCount; ++formatIndex) {
|
||||||
const auto logicalFormat = static_cast<TextureInternalFormat>(formatIndex);
|
const auto logicalFormat = static_cast<TextureInternalFormat>(formatIndex);
|
||||||
@@ -594,7 +571,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
AddFullFormatCaps(cache, renderbufferTargetIndex, formatIndex,
|
AddFullFormatCaps(cache, renderbufferTargetIndex, formatIndex,
|
||||||
GetRenderbufferFeatureCaps(logicalFormat));
|
GetRenderbufferFeatureCaps(logicalFormat));
|
||||||
const Int maxSamples =
|
const Int maxSamples =
|
||||||
GetGLESFormatMaxSamples(dynamicParameters, logicalFormat, nativeInfo.ImageFormat);
|
GetGLESFormatMaxSamples(capabilities, logicalFormat, nativeInfo.ImageFormat);
|
||||||
cache.SampleCounts[renderbufferTargetIndex][formatIndex] =
|
cache.SampleCounts[renderbufferTargetIndex][formatIndex] =
|
||||||
ProbeRenderbufferSampleCounts(gl, nativeInfo.InternalFormat, logicalFormat, maxSamples);
|
ProbeRenderbufferSampleCounts(gl, nativeInfo.InternalFormat, logicalFormat, maxSamples);
|
||||||
} else {
|
} else {
|
||||||
@@ -608,7 +585,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
LogGLESFormatCaveat(logicalFormat, renderbufferTargetIndex, fallbackInfo);
|
LogGLESFormatCaveat(logicalFormat, renderbufferTargetIndex, fallbackInfo);
|
||||||
}
|
}
|
||||||
const Int maxSamples =
|
const Int maxSamples =
|
||||||
GetGLESFormatMaxSamples(dynamicParameters, logicalFormat, fallbackInfo.ImageFormat);
|
GetGLESFormatMaxSamples(capabilities, logicalFormat, fallbackInfo.ImageFormat);
|
||||||
cache.SampleCounts[renderbufferTargetIndex][formatIndex] =
|
cache.SampleCounts[renderbufferTargetIndex][formatIndex] =
|
||||||
ProbeRenderbufferSampleCounts(gl, fallbackInfo.InternalFormat, logicalFormat, maxSamples);
|
ProbeRenderbufferSampleCounts(gl, fallbackInfo.InternalFormat, logicalFormat, maxSamples);
|
||||||
}
|
}
|
||||||
@@ -655,6 +632,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
void PopulateFormatCapabilities(const MG_External::GLESFunctionsTable& gl,
|
||||||
|
const MG_External::GLESCapabilities& capabilities,
|
||||||
|
FormatCapabilityCache& cache) {
|
||||||
|
PopulateFormatCapabilitiesImpl(gl, capabilities, cache);
|
||||||
|
}
|
||||||
|
|
||||||
BackendObject_DirectGLES::~BackendObject_DirectGLES() {
|
BackendObject_DirectGLES::~BackendObject_DirectGLES() {
|
||||||
DestroyEGLContext();
|
DestroyEGLContext();
|
||||||
}
|
}
|
||||||
@@ -695,7 +678,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// the extension list is first built).
|
// the extension list is first built).
|
||||||
UpdateAdvertisedTimerQueryExtension();
|
UpdateAdvertisedTimerQueryExtension();
|
||||||
UpdateDynamicBackendParameters();
|
UpdateDynamicBackendParameters();
|
||||||
ProbeGLESFormatCapabilities(m_GLESFunctions, MutableFormatCapabilities(), m_dynamicParameters);
|
PopulateFormatCapabilities(m_GLESFunctions, m_GLESCapabilities, MutableFormatCapabilities());
|
||||||
PrintFormatCapabilities(GetFormatCapabilities());
|
PrintFormatCapabilities(GetFormatCapabilities());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,12 @@
|
|||||||
#include <MG_Util/BackendLoaders/OpenGL/Loader.h>
|
#include <MG_Util/BackendLoaders/OpenGL/Loader.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectGLES {
|
namespace MobileGL::MG_Backend::DirectGLES {
|
||||||
|
// Populates the same format-capability cache used by backend startup. The caller
|
||||||
|
// must keep the supplied GLES context current for the duration of this call.
|
||||||
|
void PopulateFormatCapabilities(const MG_External::GLESFunctionsTable& gl,
|
||||||
|
const MG_External::GLESCapabilities& capabilities,
|
||||||
|
FormatCapabilityCache& cache);
|
||||||
|
|
||||||
class BackendObject_DirectGLES : public BackendObject {
|
class BackendObject_DirectGLES : public BackendObject {
|
||||||
public:
|
public:
|
||||||
~BackendObject_DirectGLES() override;
|
~BackendObject_DirectGLES() override;
|
||||||
|
|||||||
@@ -182,25 +182,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return MG_Util::ConvertTextureInternalFormatToVkEnum(*fallbackLogicalFormat);
|
return MG_Util::ConvertTextureInternalFormatToVkEnum(*fallbackLogicalFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr FormatCapability kVulkanProbeCapabilities[] = {
|
|
||||||
FormatCapability::Creatable,
|
|
||||||
FormatCapability::Sampled,
|
|
||||||
FormatCapability::LinearFilter,
|
|
||||||
FormatCapability::GenerateMipmap,
|
|
||||||
FormatCapability::TextureGather,
|
|
||||||
FormatCapability::TextureShadow,
|
|
||||||
FormatCapability::FramebufferRenderable,
|
|
||||||
FormatCapability::FramebufferLayered,
|
|
||||||
FormatCapability::MultisampleTexture,
|
|
||||||
FormatCapability::MultisampleRenderbuffer,
|
|
||||||
FormatCapability::ColorAttachment,
|
|
||||||
FormatCapability::DepthAttachment,
|
|
||||||
FormatCapability::StencilAttachment,
|
|
||||||
FormatCapability::TextureBuffer,
|
|
||||||
};
|
|
||||||
|
|
||||||
Bool HasNewCaveatFormatCaps(FormatCapabilityFlags nativeCaps, FormatCapabilityFlags fallbackCaps) {
|
Bool HasNewCaveatFormatCaps(FormatCapabilityFlags nativeCaps, FormatCapabilityFlags fallbackCaps) {
|
||||||
for (FormatCapability capability : kVulkanProbeCapabilities) {
|
for (FormatCapability capability : kReportedFormatCapabilities) {
|
||||||
if (HasFormatCapability(fallbackCaps, capability) &&
|
if (HasFormatCapability(fallbackCaps, capability) &&
|
||||||
!HasFormatCapability(nativeCaps, capability)) {
|
!HasFormatCapability(nativeCaps, capability)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -209,21 +192,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String GetFormatCapabilityTargetNameForLog(SizeT targetIndex) {
|
|
||||||
if (targetIndex == GetRenderbufferFormatCapabilityTargetIndex()) {
|
|
||||||
return "Renderbuffer";
|
|
||||||
}
|
|
||||||
if (targetIndex < kFormatCapabilityTextureTargetCount) {
|
|
||||||
return MG_Util::ConvertTextureTargetToString(static_cast<TextureTarget>(targetIndex));
|
|
||||||
}
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogVulkanFormatCaveat(TextureInternalFormat logicalFormat,
|
void LogVulkanFormatCaveat(TextureInternalFormat logicalFormat,
|
||||||
SizeT targetIndex,
|
SizeT targetIndex,
|
||||||
TextureInternalFormat fallbackFormat) {
|
TextureInternalFormat fallbackFormat) {
|
||||||
MGLOG_D("Caveat: %s %s not fully supported. Reason: native Vulkan format is not fully supported. Fallback: %s",
|
MGLOG_D("Caveat: %s %s not fully supported. Reason: native Vulkan format is not fully supported. Fallback: %s",
|
||||||
GetFormatCapabilityTargetNameForLog(targetIndex).c_str(),
|
GetFormatCapabilityTargetName(targetIndex).c_str(),
|
||||||
MG_Util::ConvertTextureInternalFormatToString(logicalFormat).c_str(),
|
MG_Util::ConvertTextureInternalFormatToString(logicalFormat).c_str(),
|
||||||
MG_Util::ConvertTextureInternalFormatToString(fallbackFormat).c_str());
|
MG_Util::ConvertTextureInternalFormatToString(fallbackFormat).c_str());
|
||||||
}
|
}
|
||||||
@@ -237,11 +210,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return counts;
|
return counts;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FillVulkanFormatCapabilities(VkPhysicalDevice physicalDevice,
|
void PopulateFormatCapabilitiesImpl(VkPhysicalDevice physicalDevice,
|
||||||
const DynamicBackendParameters& dynamicParameters,
|
PFN_vkGetPhysicalDeviceFormatProperties getFormatProperties,
|
||||||
|
const MG_External::VulkanCapabilities& capabilities,
|
||||||
FormatCapabilityCache& cache) {
|
FormatCapabilityCache& cache) {
|
||||||
cache.Clear();
|
cache.Clear();
|
||||||
if (physicalDevice == VK_NULL_HANDLE) {
|
if (physicalDevice == VK_NULL_HANDLE || getFormatProperties == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,12 +232,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
VkFormatProperties nativeProperties{};
|
VkFormatProperties nativeProperties{};
|
||||||
if (nativeFormat != VK_FORMAT_UNDEFINED) {
|
if (nativeFormat != VK_FORMAT_UNDEFINED) {
|
||||||
vkGetPhysicalDeviceFormatProperties(physicalDevice, nativeFormat, &nativeProperties);
|
getFormatProperties(physicalDevice, nativeFormat, &nativeProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkFormatProperties fallbackProperties{};
|
VkFormatProperties fallbackProperties{};
|
||||||
if (fallbackFormat != VK_FORMAT_UNDEFINED && fallbackFormat != nativeFormat) {
|
if (fallbackFormat != VK_FORMAT_UNDEFINED && fallbackFormat != nativeFormat) {
|
||||||
vkGetPhysicalDeviceFormatProperties(physicalDevice, fallbackFormat, &fallbackProperties);
|
getFormatProperties(physicalDevice, fallbackFormat, &fallbackProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (SizeT targetIndex = 0; targetIndex < kFormatCapabilityTextureTargetCount; ++targetIndex) {
|
for (SizeT targetIndex = 0; targetIndex < kFormatCapabilityTextureTargetCount; ++targetIndex) {
|
||||||
@@ -289,11 +263,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
const Bool isDepth = MG_Util::IsDepthFormatInternalFormat(logicalFormat);
|
const Bool isDepth = MG_Util::IsDepthFormatInternalFormat(logicalFormat);
|
||||||
const Bool isStencil = MG_Util::IsStencilFormatInternalFormat(logicalFormat);
|
const Bool isStencil = MG_Util::IsStencilFormatInternalFormat(logicalFormat);
|
||||||
const Bool isInteger = IsIntegerInternalFormat(logicalFormat);
|
const Bool isInteger = IsIntegerInternalFormat(logicalFormat);
|
||||||
Int maxSamples = dynamicParameters.MaxColorTextureSamples;
|
Int maxSamples = capabilities.MaxColorTextureSamples;
|
||||||
if (isDepth || isStencil) {
|
if (isDepth || isStencil) {
|
||||||
maxSamples = dynamicParameters.MaxDepthTextureSamples;
|
maxSamples = capabilities.MaxDepthTextureSamples;
|
||||||
} else if (isInteger) {
|
} else if (isInteger) {
|
||||||
maxSamples = dynamicParameters.MaxIntegerSamples;
|
maxSamples = capabilities.MaxIntegerSamples;
|
||||||
}
|
}
|
||||||
cache.SampleCounts[targetIndex][formatIndex] = BuildSampleCounts(maxSamples);
|
cache.SampleCounts[targetIndex][formatIndex] = BuildSampleCounts(maxSamples);
|
||||||
}
|
}
|
||||||
@@ -332,12 +306,19 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
cache.CaveatCaps[renderbufferTargetIndex][formatIndex];
|
cache.CaveatCaps[renderbufferTargetIndex][formatIndex];
|
||||||
if (HasFormatCapability(rbCaps, FormatCapability::MultisampleRenderbuffer)) {
|
if (HasFormatCapability(rbCaps, FormatCapability::MultisampleRenderbuffer)) {
|
||||||
cache.SampleCounts[renderbufferTargetIndex][formatIndex] =
|
cache.SampleCounts[renderbufferTargetIndex][formatIndex] =
|
||||||
BuildSampleCounts(dynamicParameters.MaxFramebufferSamples);
|
BuildSampleCounts(capabilities.MaxFramebufferSamples);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
void PopulateFormatCapabilities(VkPhysicalDevice physicalDevice,
|
||||||
|
PFN_vkGetPhysicalDeviceFormatProperties getFormatProperties,
|
||||||
|
const MG_External::VulkanCapabilities& capabilities,
|
||||||
|
FormatCapabilityCache& cache) {
|
||||||
|
PopulateFormatCapabilitiesImpl(physicalDevice, getFormatProperties, capabilities, cache);
|
||||||
|
}
|
||||||
|
|
||||||
BackendObject_DirectVulkan::~BackendObject_DirectVulkan() = default;
|
BackendObject_DirectVulkan::~BackendObject_DirectVulkan() = default;
|
||||||
|
|
||||||
BackendObject_DirectVulkan::BackendObject_DirectVulkan(): m_rendererInfo{GetRendererIdentity()} {}
|
BackendObject_DirectVulkan::BackendObject_DirectVulkan(): m_rendererInfo{GetRendererIdentity()} {}
|
||||||
@@ -394,7 +375,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
UpdateDynamicBackendParameters();
|
UpdateDynamicBackendParameters();
|
||||||
UpdateAdvertisedExtensions();
|
UpdateAdvertisedExtensions();
|
||||||
FillVulkanFormatCapabilities(physicalDevice.handle, m_dynamicParameters, MutableFormatCapabilities());
|
PopulateFormatCapabilities(physicalDevice.handle, vkGetPhysicalDeviceFormatProperties, m_vulkanCaps,
|
||||||
|
MutableFormatCapabilities());
|
||||||
PrintFormatCapabilities(GetFormatCapabilities());
|
PrintFormatCapabilities(GetFormatCapabilities());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,14 @@
|
|||||||
#include <MG_Util/BackendLoaders/Vulkan/Loader.h>
|
#include <MG_Util/BackendLoaders/Vulkan/Loader.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
|
// Populates the same format-capability cache used by backend startup. Passing the
|
||||||
|
// instance-resolved function keeps standalone callers independent of global loader
|
||||||
|
// initialization; the physical device must remain valid for the duration of the call.
|
||||||
|
void PopulateFormatCapabilities(VkPhysicalDevice physicalDevice,
|
||||||
|
PFN_vkGetPhysicalDeviceFormatProperties getFormatProperties,
|
||||||
|
const MG_External::VulkanCapabilities& capabilities,
|
||||||
|
FormatCapabilityCache& cache);
|
||||||
|
|
||||||
class BackendObject_DirectVulkan : public BackendObject {
|
class BackendObject_DirectVulkan : public BackendObject {
|
||||||
public:
|
public:
|
||||||
BackendObject_DirectVulkan();
|
BackendObject_DirectVulkan();
|
||||||
|
|||||||
@@ -525,6 +525,9 @@ namespace MobileGL::MG_Util::SelfTest {
|
|||||||
summary.capsValid = true;
|
summary.capsValid = true;
|
||||||
const MG_External::GLESCapabilities& caps = summary.caps;
|
const MG_External::GLESCapabilities& caps = summary.caps;
|
||||||
builder.report.rendererInfo = format("{} ({})", caps.GLESRendererString, caps.GLESVersionString);
|
builder.report.rendererInfo = format("{} ({})", caps.GLESRendererString, caps.GLESVersionString);
|
||||||
|
builder.report.formatCapabilities.emplace();
|
||||||
|
MG_Backend::DirectGLES::PopulateFormatCapabilities(
|
||||||
|
glesFuncs, caps, builder.report.formatCapabilities.value());
|
||||||
EvaluateGlesChecklist(builder, caps, glesFuncs);
|
EvaluateGlesChecklist(builder, caps, glesFuncs);
|
||||||
ProbeGlesTimerQuery(builder, caps, glesFuncs);
|
ProbeGlesTimerQuery(builder, caps, glesFuncs);
|
||||||
} while (false);
|
} while (false);
|
||||||
@@ -980,6 +983,9 @@ namespace MobileGL::MG_Util::SelfTest {
|
|||||||
getInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2"));
|
getInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2"));
|
||||||
const auto vkGetPhysicalDeviceProperties2Fn = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(
|
const auto vkGetPhysicalDeviceProperties2Fn = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(
|
||||||
getInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2"));
|
getInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2"));
|
||||||
|
const auto vkGetPhysicalDeviceFormatPropertiesFn =
|
||||||
|
reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties>(
|
||||||
|
getInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties"));
|
||||||
|
|
||||||
// The instance is destroyed from a scope guard so it is released on every early-return
|
// The instance is destroyed from a scope guard so it is released on every early-return
|
||||||
// path and even if a String/format allocation throws while report rows are being built.
|
// path and even if a String/format allocation throws while report rows are being built.
|
||||||
@@ -1059,6 +1065,14 @@ namespace MobileGL::MG_Util::SelfTest {
|
|||||||
summary.deviceName = String(properties.deviceName);
|
summary.deviceName = String(properties.deviceName);
|
||||||
summary.apiVersionString = VkApiVersionToString(properties.apiVersion);
|
summary.apiVersionString = VkApiVersionToString(properties.apiVersion);
|
||||||
summary.driverVersionString = driverVersionString;
|
summary.driverVersionString = driverVersionString;
|
||||||
|
if (vkGetPhysicalDeviceFormatPropertiesFn != nullptr) {
|
||||||
|
MG_External::VulkanCapabilities formatProbeCapabilities{};
|
||||||
|
BackendLoader::FillInVulkanCapabilities(formatProbeCapabilities, properties);
|
||||||
|
builder.report.formatCapabilities.emplace();
|
||||||
|
MG_Backend::DirectVulkan::PopulateFormatCapabilities(
|
||||||
|
physicalDevice, vkGetPhysicalDeviceFormatPropertiesFn, formatProbeCapabilities,
|
||||||
|
builder.report.formatCapabilities.value());
|
||||||
|
}
|
||||||
|
|
||||||
// The chosen-device facts (name, enumeration count, graphics queue) ride along
|
// The chosen-device facts (name, enumeration count, graphics queue) ride along
|
||||||
// on both outcomes so the device API verdict never hides them.
|
// on both outcomes so the device API verdict never hides them.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
#include <MG_Backend/BackendObject.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Util::SelfTest {
|
namespace MobileGL::MG_Util::SelfTest {
|
||||||
// One row of a backend power-on self-test (POST) report.
|
// One row of a backend power-on self-test (POST) report.
|
||||||
@@ -33,6 +34,7 @@ namespace MobileGL::MG_Util::SelfTest {
|
|||||||
String verdict = "UNSUPPORTED"; // "OK" | "DEGRADED" | "UNSUPPORTED"
|
String verdict = "UNSUPPORTED"; // "OK" | "DEGRADED" | "UNSUPPORTED"
|
||||||
String rendererInfo;
|
String rendererInfo;
|
||||||
Vector<PostCheck> checks;
|
Vector<PostCheck> checks;
|
||||||
|
Optional<MG_Backend::FormatCapabilityCache> formatCapabilities;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Probes the DEVICE GLES driver with self-contained EGL boilerplate (1x1 pbuffer
|
// Probes the DEVICE GLES driver with self-contained EGL boilerplate (1x1 pbuffer
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
|
|
||||||
#include "DriverPost.h"
|
#include "DriverPost.h"
|
||||||
|
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
|
||||||
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
|
||||||
@@ -19,6 +20,9 @@ namespace {
|
|||||||
using MobileGL::SizeT;
|
using MobileGL::SizeT;
|
||||||
using MobileGL::String;
|
using MobileGL::String;
|
||||||
using MobileGL::StringStream;
|
using MobileGL::StringStream;
|
||||||
|
using MobileGL::Uint64;
|
||||||
|
using MobileGL::MG_Backend::FormatCapabilityCache;
|
||||||
|
using MobileGL::MG_Backend::FormatCapabilityFlags;
|
||||||
using MobileGL::MG_Util::SelfTest::BackendPostReport;
|
using MobileGL::MG_Util::SelfTest::BackendPostReport;
|
||||||
using MobileGL::MG_Util::SelfTest::PostCheck;
|
using MobileGL::MG_Util::SelfTest::PostCheck;
|
||||||
|
|
||||||
@@ -70,6 +74,55 @@ namespace {
|
|||||||
out << '"' << EscapeJsonString(value) << '"';
|
out << '"' << EscapeJsonString(value) << '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Uint64 BuildFormatCapabilityMask(FormatCapabilityFlags capabilities) {
|
||||||
|
Uint64 mask = 0;
|
||||||
|
for (SizeT capabilityIndex = 0;
|
||||||
|
capabilityIndex < MobileGL::MG_Backend::kReportedFormatCapabilities.size(); ++capabilityIndex) {
|
||||||
|
if (MobileGL::MG_Backend::HasFormatCapability(
|
||||||
|
capabilities, MobileGL::MG_Backend::kReportedFormatCapabilities[capabilityIndex])) {
|
||||||
|
mask |= 1ull << capabilityIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppendFormatCapabilitiesJson(StringStream& out, const FormatCapabilityCache& cache) {
|
||||||
|
out << ",\"formatCapabilities\":{\"capabilities\":[";
|
||||||
|
for (SizeT capabilityIndex = 0;
|
||||||
|
capabilityIndex < MobileGL::MG_Backend::kReportedFormatCapabilities.size(); ++capabilityIndex) {
|
||||||
|
if (capabilityIndex != 0) {
|
||||||
|
out << ',';
|
||||||
|
}
|
||||||
|
AppendJsonString(
|
||||||
|
out, MobileGL::MG_Backend::GetFormatCapabilityName(
|
||||||
|
MobileGL::MG_Backend::kReportedFormatCapabilities[capabilityIndex]));
|
||||||
|
}
|
||||||
|
out << "],\"targets\":[";
|
||||||
|
for (SizeT targetIndex = 0; targetIndex < MobileGL::MG_Backend::kFormatCapabilityTargetCount;
|
||||||
|
++targetIndex) {
|
||||||
|
if (targetIndex != 0) {
|
||||||
|
out << ',';
|
||||||
|
}
|
||||||
|
out << "{\"name\":";
|
||||||
|
AppendJsonString(out, MobileGL::MG_Backend::GetFormatCapabilityTargetName(targetIndex));
|
||||||
|
out << ",\"rows\":[";
|
||||||
|
for (SizeT formatIndex = 0; formatIndex < MobileGL::MG_Backend::kFormatCapabilityFormatCount;
|
||||||
|
++formatIndex) {
|
||||||
|
if (formatIndex != 0) {
|
||||||
|
out << ',';
|
||||||
|
}
|
||||||
|
out << '[';
|
||||||
|
AppendJsonString(
|
||||||
|
out, MobileGL::MG_Util::ConvertTextureInternalFormatToString(
|
||||||
|
static_cast<MobileGL::TextureInternalFormat>(formatIndex)));
|
||||||
|
out << ',' << BuildFormatCapabilityMask(cache.FullCaps[targetIndex][formatIndex]);
|
||||||
|
out << ',' << BuildFormatCapabilityMask(cache.CaveatCaps[targetIndex][formatIndex]) << ']';
|
||||||
|
}
|
||||||
|
out << "]}";
|
||||||
|
}
|
||||||
|
out << "]}";
|
||||||
|
}
|
||||||
|
|
||||||
void AppendBackendReportJson(StringStream& out, const BackendPostReport& report) {
|
void AppendBackendReportJson(StringStream& out, const BackendPostReport& report) {
|
||||||
out << "{\"available\":" << (report.available ? "true" : "false");
|
out << "{\"available\":" << (report.available ? "true" : "false");
|
||||||
out << ",\"verdict\":";
|
out << ",\"verdict\":";
|
||||||
@@ -90,7 +143,11 @@ namespace {
|
|||||||
AppendJsonString(out, check.detail);
|
AppendJsonString(out, check.detail);
|
||||||
out << '}';
|
out << '}';
|
||||||
}
|
}
|
||||||
out << "]}";
|
out << ']';
|
||||||
|
if (report.formatCapabilities.has_value()) {
|
||||||
|
AppendFormatCapabilitiesJson(out, report.formatCapabilities.value());
|
||||||
|
}
|
||||||
|
out << '}';
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import android.util.Log;
|
|||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.widget.HorizontalScrollView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ScrollView;
|
import android.widget.ScrollView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@@ -30,6 +31,15 @@ public final class PostActivity extends Activity {
|
|||||||
private static final int COLOR_DETAIL = 0xFFBBBBBB;
|
private static final int COLOR_DETAIL = 0xFFBBBBBB;
|
||||||
private static final int COLOR_ROW_EVEN = 0xFF1A1A1A;
|
private static final int COLOR_ROW_EVEN = 0xFF1A1A1A;
|
||||||
private static final int COLOR_ROW_ODD = 0xFF121212;
|
private static final int COLOR_ROW_ODD = 0xFF121212;
|
||||||
|
private static final int COLOR_TABLE_HEADER = 0xFF303030;
|
||||||
|
private static final int COLOR_FORMAT_CELL = 0xFF242424;
|
||||||
|
private static final int COLOR_CAPABILITY_FULL = 0xFF2E7D32;
|
||||||
|
private static final int COLOR_CAPABILITY_CAVEAT = 0xFFFBC02D;
|
||||||
|
private static final int COLOR_CAPABILITY_NONE = 0xFFC62828;
|
||||||
|
|
||||||
|
private static final int FORMAT_COLUMN_WIDTH_DP = 152;
|
||||||
|
private static final int CAPABILITY_COLUMN_WIDTH_DP = 152;
|
||||||
|
private static final int CAPABILITY_ROW_HEIGHT_DP = 36;
|
||||||
|
|
||||||
private static final String INDICATOR_COLLAPSED = "▸";
|
private static final String INDICATOR_COLLAPSED = "▸";
|
||||||
private static final String INDICATOR_EXPANDED = "▾";
|
private static final String INDICATOR_EXPANDED = "▾";
|
||||||
@@ -244,9 +254,7 @@ public final class PostActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JSONArray checks = backend.optJSONArray("checks");
|
JSONArray checks = backend.optJSONArray("checks");
|
||||||
if (checks == null) {
|
if (checks != null) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
LinearLayout table = new LinearLayout(this);
|
LinearLayout table = new LinearLayout(this);
|
||||||
table.setOrientation(LinearLayout.VERTICAL);
|
table.setOrientation(LinearLayout.VERTICAL);
|
||||||
LinearLayout.LayoutParams tableParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams tableParams = new LinearLayout.LayoutParams(
|
||||||
@@ -265,6 +273,9 @@ public final class PostActivity extends Activity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderFormatCapabilities(backend.optJSONObject("formatCapabilities"));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds one two-column check row (name | status chip) to the table. Rows with
|
* Adds one two-column check row (name | status chip) to the table. Rows with
|
||||||
* a non-empty detail get a collapse indicator and toggle the detail text on tap;
|
* a non-empty detail get a collapse indicator and toggle the detail text on tap;
|
||||||
@@ -336,6 +347,178 @@ public final class PostActivity extends Activity {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Adds one initially-collapsed capability matrix for every reported target. */
|
||||||
|
private void renderFormatCapabilities(JSONObject formatCapabilities) {
|
||||||
|
addText("Format capabilities", 14, COLOR_TEXT, true, dp(16));
|
||||||
|
if (formatCapabilities == null) {
|
||||||
|
addText("Format capability table unavailable.", 12, COLOR_INFO, false, dp(4));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONArray capabilities = formatCapabilities.optJSONArray("capabilities");
|
||||||
|
JSONArray targets = formatCapabilities.optJSONArray("targets");
|
||||||
|
if (capabilities == null || capabilities.length() == 0 || targets == null || targets.length() == 0) {
|
||||||
|
addText("Format capability table is empty.", 12, COLOR_INFO, false, dp(4));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int targetIndex = 0; targetIndex < targets.length(); ++targetIndex) {
|
||||||
|
JSONObject target = targets.optJSONObject(targetIndex);
|
||||||
|
if (target != null) {
|
||||||
|
addFormatTargetTable(target, capabilities);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a target header whose table is created only while expanded. Removing the
|
||||||
|
* table again on collapse avoids retaining all status cells for both backends.
|
||||||
|
*/
|
||||||
|
private void addFormatTargetTable(JSONObject target, JSONArray capabilities) {
|
||||||
|
String targetName = target.optString("name", "Unknown target");
|
||||||
|
JSONArray rows = target.optJSONArray("rows");
|
||||||
|
int formatCount = rows == null ? 0 : rows.length();
|
||||||
|
|
||||||
|
LinearLayout section = new LinearLayout(this);
|
||||||
|
section.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
LinearLayout.LayoutParams sectionParams = new LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
sectionParams.topMargin = dp(6);
|
||||||
|
contentLayout.addView(section, sectionParams);
|
||||||
|
|
||||||
|
TextView toggleView = makeText(
|
||||||
|
INDICATOR_COLLAPSED + " " + targetName + " (" + formatCount + " formats)",
|
||||||
|
12,
|
||||||
|
COLOR_TEXT,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
toggleView.setBackgroundColor(COLOR_ROW_EVEN);
|
||||||
|
toggleView.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
toggleView.setMinimumHeight(dp(44));
|
||||||
|
toggleView.setPadding(dp(10), dp(6), dp(10), dp(6));
|
||||||
|
section.addView(toggleView, new LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
));
|
||||||
|
|
||||||
|
toggleView.setOnClickListener(view -> {
|
||||||
|
boolean expanded = section.getChildCount() > 1;
|
||||||
|
if (expanded) {
|
||||||
|
section.removeViews(1, section.getChildCount() - 1);
|
||||||
|
toggleView.setText(
|
||||||
|
INDICATOR_COLLAPSED + " " + targetName + " (" + formatCount + " formats)"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.addView(buildFormatCapabilityTable(capabilities, rows), new LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
));
|
||||||
|
toggleView.setText(
|
||||||
|
INDICATOR_EXPANDED + " " + targetName + " (" + formatCount + " formats)"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Builds the horizontally-scrollable table for one target. */
|
||||||
|
private HorizontalScrollView buildFormatCapabilityTable(JSONArray capabilities, JSONArray rows) {
|
||||||
|
HorizontalScrollView scrollView = new HorizontalScrollView(this);
|
||||||
|
scrollView.setFillViewport(false);
|
||||||
|
scrollView.setHorizontalScrollBarEnabled(true);
|
||||||
|
scrollView.setPadding(0, dp(2), 0, dp(4));
|
||||||
|
|
||||||
|
LinearLayout table = new LinearLayout(this);
|
||||||
|
table.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
table.addView(buildFormatCapabilityHeader(capabilities));
|
||||||
|
|
||||||
|
if (rows != null) {
|
||||||
|
for (int rowIndex = 0; rowIndex < rows.length(); ++rowIndex) {
|
||||||
|
JSONArray row = rows.optJSONArray(rowIndex);
|
||||||
|
if (row != null) {
|
||||||
|
table.addView(buildFormatCapabilityRow(capabilities.length(), row));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollView.addView(table, new HorizontalScrollView.LayoutParams(
|
||||||
|
HorizontalScrollView.LayoutParams.WRAP_CONTENT,
|
||||||
|
HorizontalScrollView.LayoutParams.WRAP_CONTENT
|
||||||
|
));
|
||||||
|
return scrollView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LinearLayout buildFormatCapabilityHeader(JSONArray capabilities) {
|
||||||
|
LinearLayout header = new LinearLayout(this);
|
||||||
|
header.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
addFormatTableCell(header, "Format", FORMAT_COLUMN_WIDTH_DP, COLOR_TABLE_HEADER, COLOR_TEXT, true);
|
||||||
|
for (int capabilityIndex = 0; capabilityIndex < capabilities.length(); ++capabilityIndex) {
|
||||||
|
addFormatTableCell(
|
||||||
|
header,
|
||||||
|
capabilities.optString(capabilityIndex, "Capability " + capabilityIndex),
|
||||||
|
CAPABILITY_COLUMN_WIDTH_DP,
|
||||||
|
COLOR_TABLE_HEADER,
|
||||||
|
COLOR_TEXT,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LinearLayout buildFormatCapabilityRow(int capabilityCount, JSONArray row) {
|
||||||
|
LinearLayout line = new LinearLayout(this);
|
||||||
|
line.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
|
||||||
|
addFormatTableCell(
|
||||||
|
line,
|
||||||
|
row.optString(0, "Unknown"),
|
||||||
|
FORMAT_COLUMN_WIDTH_DP,
|
||||||
|
COLOR_FORMAT_CELL,
|
||||||
|
COLOR_TEXT,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
long fullMask = row.optLong(1, 0L);
|
||||||
|
long caveatMask = row.optLong(2, 0L);
|
||||||
|
for (int capabilityIndex = 0; capabilityIndex < capabilityCount; ++capabilityIndex) {
|
||||||
|
long capabilityBit = capabilityIndex < Long.SIZE ? 1L << capabilityIndex : 0L;
|
||||||
|
boolean full = capabilityBit != 0L && (fullMask & capabilityBit) != 0L;
|
||||||
|
boolean caveat = !full && capabilityBit != 0L && (caveatMask & capabilityBit) != 0L;
|
||||||
|
addFormatTableCell(
|
||||||
|
line,
|
||||||
|
full ? "Full" : caveat ? "Caveat" : "None",
|
||||||
|
CAPABILITY_COLUMN_WIDTH_DP,
|
||||||
|
full ? COLOR_CAPABILITY_FULL : caveat ? COLOR_CAPABILITY_CAVEAT : COLOR_CAPABILITY_NONE,
|
||||||
|
caveat ? 0xFF000000 : 0xFFFFFFFF,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFormatTableCell(LinearLayout row,
|
||||||
|
String text,
|
||||||
|
int widthDp,
|
||||||
|
int backgroundColor,
|
||||||
|
int textColor,
|
||||||
|
boolean bold) {
|
||||||
|
TextView cell = makeText(text, 10, textColor, bold);
|
||||||
|
cell.setBackgroundColor(backgroundColor);
|
||||||
|
cell.setGravity(Gravity.CENTER);
|
||||||
|
cell.setSingleLine(true);
|
||||||
|
cell.setPadding(dp(6), 0, dp(6), 0);
|
||||||
|
|
||||||
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||||
|
dp(widthDp),
|
||||||
|
dp(CAPABILITY_ROW_HEIGHT_DP)
|
||||||
|
);
|
||||||
|
params.rightMargin = dp(1);
|
||||||
|
params.bottomMargin = dp(1);
|
||||||
|
row.addView(cell, params);
|
||||||
|
}
|
||||||
|
|
||||||
/** Adds the collapsed "Raw report" toggle plus the (initially hidden) raw JSON dump. */
|
/** Adds the collapsed "Raw report" toggle plus the (initially hidden) raw JSON dump. */
|
||||||
private void addRawJsonSection(String json) {
|
private void addRawJsonSection(String json) {
|
||||||
TextView toggleView = addText(INDICATOR_COLLAPSED + " Raw report (tap to expand)", 12, COLOR_INFO, true, dp(24));
|
TextView toggleView = addText(INDICATOR_COLLAPSED + " Raw report (tap to expand)", 12, COLOR_INFO, true, dp(24));
|
||||||
|
|||||||
Reference in New Issue
Block a user