[Fix] (MG_Impl, MG_State, MG_Backend, MG_Util): Do source audit by Codex.

This commit is contained in:
BZLZHH
2026-06-09 15:34:19 +08:00
parent be3c3eb9bb
commit 727939af5b
93 changed files with 6019 additions and 731 deletions
+17
View File
@@ -15,7 +15,16 @@
#include <MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h>
namespace MobileGL {
namespace {
Bool g_isInitialized = false;
}
void Initialize() {
if (g_isInitialized) {
MGLOG_D("MobileGL already initialized; skipping duplicate Initialize()");
return;
}
MG_Util::Debug::InitFile();
MGLOG_I("Initializing MobileGL...");
MG_ConfigLoader::Init();
@@ -28,16 +37,24 @@ namespace MobileGL {
MGLOG_D("MG_Impl initialized");
glslang::InitializeProcess();
MGLOG_D("glslang initialized");
g_isInitialized = true;
MGLOG_I("MobileGL initialized");
}
void Destroy() {
if (!g_isInitialized) {
return;
}
MGLOG_I("MobileGL closing...");
glslang::FinalizeProcess();
MG_Backend::pActiveBackendObject.reset();
MG_State::pGLContext.reset();
MG_State::pEGLContext.reset();
MG_Impl::GLImpl::TextureImpl::pProxyTextureManager.reset();
MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo.reset();
MG_Backend::gBackendFunctionsTable = {};
g_isInitialized = false;
MG_Util::Debug::Close();
// TODO: add and use Destroy functions for other subsystems
+48
View File
@@ -90,6 +90,54 @@ namespace MobileGL {
struct DynamicBackendParameters {
SizeT UniformBufferOffsetAlignment = 256;
Float AliasedLineWidthRangeMin = 1.0f;
Float AliasedLineWidthRangeMax = 1.0f;
Float SmoothLineWidthRangeMin = 1.0f;
Float SmoothLineWidthRangeMax = 1.0f;
Float SmoothLineWidthGranularity = 1.0f;
Float PointSizeRangeMin = 1.0f;
Float PointSizeRangeMax = 1.0f;
Float PointSizeGranularity = 1.0f;
Int Max3DTextureSize = 16384;
Int MaxArrayTextureLayers = 2048;
Int MaxCubeMapTextureSize = 16384;
Int MaxFramebufferWidth = 16384;
Int MaxFramebufferHeight = 16384;
Int MaxFramebufferLayers = 2048;
Int MaxRenderbufferSize = 16384;
Int MaxTextureSize = 16384;
Int MaxColorTextureSamples = 1;
Int MaxDepthTextureSamples = 1;
Int MaxFramebufferSamples = 1;
Int MaxIntegerSamples = 1;
Int MaxSamples = 1;
Int MaxSampleMaskWords = 1;
Int MaxTextureImageUnits = 32;
Int MaxVertexTextureImageUnits = 32;
Int MaxComputeTextureImageUnits = 32;
Int MaxCombinedTextureImageUnits = 192;
Int MaxVertexAttribs = 16;
Int MaxComputeShaderStorageBlocks = 8;
Int MaxCombinedShaderStorageBlocks = 32;
Int MaxComputeUniformBlocks = 12;
Int MaxComputeWorkGroupInvocations = 128;
Int MaxShaderStorageBufferBindings = 8;
Int MaxTextureBufferSize = 65536;
Int MaxUniformBufferBindings = 24;
Int MaxUniformBlockSize = 16384;
Int MaxImageUnits = 8;
Int MaxCombinedImageUniforms = 8;
Int MaxComputeImageUniforms = 8;
Int MaxDrawBuffers = 8;
Int MaxColorAttachments = 8;
Int MaxClipDistances = 8;
Int MaxViewports = 16;
Int MaxViewportWidth = 16384;
Int MaxViewportHeight = 16384;
Float ViewportBoundsRangeMin = 0.0f;
Float ViewportBoundsRangeMax = 0.0f;
Int ViewportSubpixelBits = 0;
Bool SupportsWideLines = false;
};
enum class WindowBackend {
@@ -97,6 +97,21 @@ namespace MobileGL::MG_Backend::DirectGLES {
return BackendObject::CreateEGLWindowSurface(handle);
}
Bool BackendObject_DirectGLES::CreateEGLPbufferSurface(EGLint width, EGLint height) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (!m_initialized) {
MGLOG_E("DirectGLES backend not initialized");
return false;
}
if (m_eglSurfaceInitialized) {
DestroyEGLContext();
ResetEGLRuntimeState();
}
return BackendObject::CreateEGLPbufferSurface(width, height);
}
Bool BackendObject_DirectGLES::InitPbufferSurface(EGLint width, EGLint height) {
return DirectGLES::InitPbufferSurface(width, height);
}
@@ -214,6 +229,55 @@ namespace MobileGL::MG_Backend::DirectGLES {
void BackendObject_DirectGLES::UpdateDynamicBackendParameters() {
m_dynamicParameters.UniformBufferOffsetAlignment = m_GLESCapabilities.UniformBufferOffsetAlignment;
m_dynamicParameters.AliasedLineWidthRangeMin = m_GLESCapabilities.AliasedLineWidthRangeMin;
m_dynamicParameters.AliasedLineWidthRangeMax = m_GLESCapabilities.AliasedLineWidthRangeMax;
m_dynamicParameters.SmoothLineWidthRangeMin = m_GLESCapabilities.SmoothLineWidthRangeMin;
m_dynamicParameters.SmoothLineWidthRangeMax = m_GLESCapabilities.SmoothLineWidthRangeMax;
m_dynamicParameters.SmoothLineWidthGranularity = m_GLESCapabilities.SmoothLineWidthGranularity;
m_dynamicParameters.PointSizeRangeMin = m_GLESCapabilities.PointSizeRangeMin;
m_dynamicParameters.PointSizeRangeMax = m_GLESCapabilities.PointSizeRangeMax;
m_dynamicParameters.PointSizeGranularity = m_GLESCapabilities.PointSizeGranularity;
m_dynamicParameters.Max3DTextureSize = m_GLESCapabilities.Max3DTextureSize;
m_dynamicParameters.MaxArrayTextureLayers = m_GLESCapabilities.MaxArrayTextureLayers;
m_dynamicParameters.MaxCubeMapTextureSize = m_GLESCapabilities.MaxCubeMapTextureSize;
m_dynamicParameters.MaxFramebufferWidth = m_GLESCapabilities.MaxFramebufferWidth;
m_dynamicParameters.MaxFramebufferHeight = m_GLESCapabilities.MaxFramebufferHeight;
m_dynamicParameters.MaxFramebufferLayers = m_GLESCapabilities.MaxFramebufferLayers;
m_dynamicParameters.MaxRenderbufferSize = m_GLESCapabilities.MaxRenderbufferSize;
m_dynamicParameters.MaxTextureSize = m_GLESCapabilities.MaxTextureSize;
m_dynamicParameters.MaxColorTextureSamples = m_GLESCapabilities.MaxColorTextureSamples;
m_dynamicParameters.MaxDepthTextureSamples = m_GLESCapabilities.MaxDepthTextureSamples;
m_dynamicParameters.MaxFramebufferSamples = m_GLESCapabilities.MaxFramebufferSamples;
m_dynamicParameters.MaxIntegerSamples = m_GLESCapabilities.MaxIntegerSamples;
m_dynamicParameters.MaxSamples = m_GLESCapabilities.MaxSamples;
m_dynamicParameters.MaxSampleMaskWords = m_GLESCapabilities.MaxSampleMaskWords;
m_dynamicParameters.MaxTextureImageUnits = m_GLESCapabilities.MaxTextureImageUnits;
m_dynamicParameters.MaxVertexTextureImageUnits = m_GLESCapabilities.MaxVertexTextureImageUnits;
m_dynamicParameters.MaxComputeTextureImageUnits = m_GLESCapabilities.MaxComputeTextureImageUnits;
m_dynamicParameters.MaxCombinedTextureImageUnits = m_GLESCapabilities.MaxCombinedTextureImageUnits;
m_dynamicParameters.MaxVertexAttribs = m_GLESCapabilities.MaxVertexAttribs;
m_dynamicParameters.MaxComputeShaderStorageBlocks = m_GLESCapabilities.MaxComputeShaderStorageBlocks;
m_dynamicParameters.MaxCombinedShaderStorageBlocks = m_GLESCapabilities.MaxCombinedShaderStorageBlocks;
m_dynamicParameters.MaxComputeUniformBlocks = m_GLESCapabilities.MaxComputeUniformBlocks;
m_dynamicParameters.MaxComputeWorkGroupInvocations = m_GLESCapabilities.MaxComputeWorkGroupInvocations;
m_dynamicParameters.MaxShaderStorageBufferBindings = m_GLESCapabilities.MaxShaderStorageBufferBindings;
m_dynamicParameters.MaxTextureBufferSize = m_GLESCapabilities.MaxTextureBufferSize;
m_dynamicParameters.MaxUniformBufferBindings = m_GLESCapabilities.MaxUniformBufferBindings;
m_dynamicParameters.MaxUniformBlockSize = m_GLESCapabilities.MaxUniformBlockSize;
m_dynamicParameters.MaxImageUnits = m_GLESCapabilities.MaxImageUnits;
m_dynamicParameters.MaxCombinedImageUniforms = m_GLESCapabilities.MaxCombinedImageUniforms;
m_dynamicParameters.MaxComputeImageUniforms = m_GLESCapabilities.MaxComputeImageUniforms;
m_dynamicParameters.MaxDrawBuffers = m_GLESCapabilities.MaxDrawBuffers;
m_dynamicParameters.MaxColorAttachments = m_GLESCapabilities.MaxColorAttachments;
m_dynamicParameters.MaxClipDistances = m_GLESCapabilities.MaxClipDistances;
m_dynamicParameters.MaxViewports = m_GLESCapabilities.MaxViewports;
m_dynamicParameters.MaxViewportWidth = m_GLESCapabilities.MaxViewportWidth;
m_dynamicParameters.MaxViewportHeight = m_GLESCapabilities.MaxViewportHeight;
m_dynamicParameters.ViewportBoundsRangeMin = m_GLESCapabilities.ViewportBoundsRangeMin;
m_dynamicParameters.ViewportBoundsRangeMax = m_GLESCapabilities.ViewportBoundsRangeMax;
m_dynamicParameters.ViewportSubpixelBits = m_GLESCapabilities.ViewportSubpixelBits;
m_dynamicParameters.SupportsWideLines =
m_GLESCapabilities.AliasedLineWidthRangeMax > 1.0f || m_GLESCapabilities.SmoothLineWidthRangeMax > 1.0f;
}
const MG_External::GLESFunctionsTable& BackendObject_DirectGLES::GetGLESFunctions() const {
@@ -21,6 +21,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
Bool InitWindowSurface() override;
Bool InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) override;
Bool CreateEGLWindowSurface(const WindowHandle& handle) override;
Bool CreateEGLPbufferSurface(EGLint width, EGLint height) override;
Bool MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) override;
Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) override;
void ReleaseEGLResources() override;
@@ -415,7 +415,16 @@ namespace MobileGL::MG_Backend::DirectGLES {
} \
}
SYNC_CAPABILITY(DepthTest, GL_DEPTH_TEST);
SYNC_CAPABILITY(ColorLogicOp, GL_COLOR_LOGIC_OP);
SYNC_CAPABILITY(Dither, GL_DITHER);
SYNC_CAPABILITY(Multisample, GL_MULTISAMPLE);
SYNC_CAPABILITY(SampleAlphaToCoverage, GL_SAMPLE_ALPHA_TO_COVERAGE);
SYNC_CAPABILITY(SampleCoverage, GL_SAMPLE_COVERAGE);
SYNC_CAPABILITY(SampleMask, GL_SAMPLE_MASK);
SYNC_CAPABILITY(PolygonOffsetFill, GL_POLYGON_OFFSET_FILL);
SYNC_CAPABILITY(RasterizerDiscard, GL_RASTERIZER_DISCARD);
SYNC_CAPABILITY(ScissorTest, GL_SCISSOR_TEST);
SYNC_CAPABILITY(StencilTest, GL_STENCIL_TEST);
SYNC_CAPABILITY(CullFace, GL_CULL_FACE);
#undef SYNC_CAPABILITY
@@ -528,6 +537,34 @@ namespace MobileGL::MG_Backend::DirectGLES {
if (parameters.DepthMask != g_syncedRenderStateParameters.DepthMask) {
g_GLESFuncs.glDepthMask(parameters.DepthMask ? GL_TRUE : GL_FALSE);
}
if (parameters.DepthRange != g_syncedRenderStateParameters.DepthRange) {
g_GLESFuncs.glDepthRangef(parameters.DepthRange.x(), parameters.DepthRange.y());
}
}
{ // Stencil state
for (SizeT faceIndex = 0; faceIndex < parameters.StencilStates.size(); ++faceIndex) {
const StencilFaceState& current = parameters.StencilStates[faceIndex];
const StencilFaceState& synced = g_syncedRenderStateParameters.StencilStates[faceIndex];
const GLenum glFace = faceIndex == 0 ? GL_FRONT : GL_BACK;
if (current.Func != synced.Func || current.Ref != synced.Ref ||
current.ValueMask != synced.ValueMask) {
g_GLESFuncs.glStencilFuncSeparate(
glFace, MG_Util::ConvertDepthTestFuncToGLEnum(current.Func), current.Ref,
current.ValueMask);
}
if (current.WriteMask != synced.WriteMask) {
g_GLESFuncs.glStencilMaskSeparate(glFace, current.WriteMask);
}
if (current.FailOp != synced.FailOp || current.PassDepthFailOp != synced.PassDepthFailOp ||
current.PassDepthPassOp != synced.PassDepthPassOp) {
g_GLESFuncs.glStencilOpSeparate(
glFace, MG_Util::ConvertStencilOperationToGLEnum(current.FailOp),
MG_Util::ConvertStencilOperationToGLEnum(current.PassDepthFailOp),
MG_Util::ConvertStencilOperationToGLEnum(current.PassDepthPassOp));
}
}
}
{ // Color mask
@@ -546,6 +583,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
if (parameters.ClearDepth != g_syncedRenderStateParameters.ClearDepth) {
g_GLESFuncs.glClearDepthf(parameters.ClearDepth);
}
if (parameters.BlendColor != g_syncedRenderStateParameters.BlendColor) {
const FloatVec4& blendColor = parameters.BlendColor;
g_GLESFuncs.glBlendColor(blendColor.x(), blendColor.y(), blendColor.z(), blendColor.w());
}
}
{ // Cull face mode
@@ -566,6 +607,45 @@ namespace MobileGL::MG_Backend::DirectGLES {
}
}
{ // Logic op
if (parameters.LogicOp != g_syncedRenderStateParameters.LogicOp) {
g_GLESFuncs.glLogicOp(MG_Util::ConvertLogicOperationToGLEnum(parameters.LogicOp));
}
}
{ // Polygon offset
if (parameters.PolygonOffsetFactor != g_syncedRenderStateParameters.PolygonOffsetFactor ||
parameters.PolygonOffsetUnits != g_syncedRenderStateParameters.PolygonOffsetUnits) {
g_GLESFuncs.glPolygonOffset(parameters.PolygonOffsetFactor, parameters.PolygonOffsetUnits);
}
}
{ // Line width
if (parameters.LineWidth != g_syncedRenderStateParameters.LineWidth) {
g_GLESFuncs.glLineWidth(parameters.LineWidth);
}
}
{ // Point size
if (parameters.PointSize != g_syncedRenderStateParameters.PointSize) {
g_GLESFuncs.glPointSize(parameters.PointSize);
}
}
{ // Sample coverage
if (parameters.SampleCoverageValue != g_syncedRenderStateParameters.SampleCoverageValue ||
parameters.SampleCoverageInvert != g_syncedRenderStateParameters.SampleCoverageInvert) {
g_GLESFuncs.glSampleCoverage(parameters.SampleCoverageValue,
ToGLBoolean(parameters.SampleCoverageInvert));
}
}
{ // Sample mask
if (g_GLESFuncs.glSampleMaski && parameters.SampleMaskValue != g_syncedRenderStateParameters.SampleMaskValue) {
g_GLESFuncs.glSampleMaski(0, parameters.SampleMaskValue);
}
}
g_syncedRenderStateVersion = currentRenderStateVersion;
g_syncedRenderStateParameters = parameters;
g_hasSyncedRenderState = true;
+38 -8
View File
@@ -614,10 +614,27 @@ namespace MobileGL::MG_Backend::DirectGLES {
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()),
static_cast<GLsizei>(texelSize.y()), glFormat, glType,
textureMipmapObject->MapMipmapData(uploadTarget, level));
const void* mipData = textureMipmapObject->MapMipmapData(uploadTarget, level);
switch (stateTextureObject->GetTarget()) {
case TextureTarget::Texture2D:
case TextureTarget::TextureCubeMap:
g_GLESFuncs.glTexSubImage2D(glUploadTarget, static_cast<GLint>(level), 0, 0,
static_cast<GLsizei>(texelSize.x()),
static_cast<GLsizei>(texelSize.y()), glFormat, glType,
mipData);
break;
case TextureTarget::Texture3D:
g_GLESFuncs.glTexSubImage3D(glUploadTarget, static_cast<GLint>(level), 0, 0, 0,
static_cast<GLsizei>(texelSize.x()),
static_cast<GLsizei>(texelSize.y()),
static_cast<GLsizei>(texelSize.z()), glFormat, glType,
mipData);
break;
default:
MGLOG_E("Unhandled texture target %s",
MG_Util::ConvertTextureTargetToString(stateTextureObject->GetTarget()).c_str());
break;
}
textureMipmapObject->MarkStorageDirty(uploadTarget, level, false);
}
}
@@ -912,7 +929,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
return false;
}
const auto& backendTextureObject = backendTextureIt->second;
auto glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
auto glTextureTarget =
MG_Util::ConvertTextureUploadTargetToGLEnum(attachmentObject.GetTextureUploadTarget());
if (glTextureTarget == GL_UNKNOWN_MGL) {
glTextureTarget = MG_Util::ConvertTextureTargetToGLEnum(textureObject->GetTarget());
}
backendTextureObject->Bind(glTextureTarget);
g_GLESFuncs.glFramebufferTexture2D(glFBOTarget, glBackendAttachment, glTextureTarget,
backendTextureObject->GetBackendTextureId(),
@@ -1428,7 +1449,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
stateRBOObject->GetExternalIndex());
if (m_isInitialized && m_cacheInternalFormat == stateRBOObject->GetInternalFormat() &&
m_cacheWidth == stateRBOObject->GetWidth() && m_cacheHeight == stateRBOObject->GetHeight()) {
m_cacheWidth == stateRBOObject->GetWidth() && m_cacheHeight == stateRBOObject->GetHeight() &&
m_cacheSamples == stateRBOObject->GetSamples()) {
MGLOG_D("RBO %u already initialized with matching parameters, skipping re-allocation.",
stateRBOObject->GetExternalIndex());
return;
@@ -1440,15 +1462,23 @@ namespace MobileGL::MG_Backend::DirectGLES {
TextureInternalFormat internalFormat = stateRBOObject->GetInternalFormat();
Int width = static_cast<Int>(stateRBOObject->GetWidth());
Int height = static_cast<Int>(stateRBOObject->GetHeight());
Int samples = static_cast<Int>(stateRBOObject->GetSamples());
GLenum glInternalFormat, glType, glFormat;
TextureImpl::GenerateTextureFormatInfo(internalFormat, &glInternalFormat, &glFormat, &glType);
g_GLESFuncs.glRenderbufferStorage(GL_RENDERBUFFER, glInternalFormat, static_cast<GLsizei>(width),
static_cast<GLsizei>(height));
if (samples > 0) {
g_GLESFuncs.glRenderbufferStorageMultisample(
GL_RENDERBUFFER, static_cast<GLsizei>(samples), glInternalFormat, static_cast<GLsizei>(width),
static_cast<GLsizei>(height));
} else {
g_GLESFuncs.glRenderbufferStorage(GL_RENDERBUFFER, glInternalFormat, static_cast<GLsizei>(width),
static_cast<GLsizei>(height));
}
m_cacheInternalFormat = internalFormat;
m_cacheWidth = width;
m_cacheHeight = height;
m_cacheSamples = samples;
m_isInitialized = true;
MGLOG_D("RBO %u sync completed. backend ID %u", stateRBOObject->GetExternalIndex(), m_backendRBOId);
@@ -313,6 +313,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
TextureInternalFormat m_cacheInternalFormat = TextureInternalFormat::Unknown;
Int m_cacheWidth = 0;
Int m_cacheHeight = 0;
Int m_cacheSamples = 0;
};
extern StateBackendObjectRegistry<MG_State::GLState::RenderbufferObject, BackendRenderbufferObject>
+1 -1
View File
@@ -149,7 +149,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
while (GLenum err = g_GLESFuncs.glGetError() != GL_NO_ERROR) {
for (GLenum err = g_GLESFuncs.glGetError(); err != GL_NO_ERROR; err = g_GLESFuncs.glGetError()) {
MGLOG_E("-> GLES Error: %s", MG_Util::ConvertGLEnumToString(err).c_str());
}
}
@@ -207,5 +207,53 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void BackendObject_DirectVulkan::UpdateDynamicBackendParameters() {
m_dynamicParameters.UniformBufferOffsetAlignment = m_vulkanCaps.UniformBufferOffsetAlignment;
m_dynamicParameters.AliasedLineWidthRangeMin = m_vulkanCaps.AliasedLineWidthRangeMin;
m_dynamicParameters.AliasedLineWidthRangeMax = m_vulkanCaps.AliasedLineWidthRangeMax;
m_dynamicParameters.SmoothLineWidthRangeMin = m_vulkanCaps.SmoothLineWidthRangeMin;
m_dynamicParameters.SmoothLineWidthRangeMax = m_vulkanCaps.SmoothLineWidthRangeMax;
m_dynamicParameters.SmoothLineWidthGranularity = m_vulkanCaps.SmoothLineWidthGranularity;
m_dynamicParameters.PointSizeRangeMin = m_vulkanCaps.PointSizeRangeMin;
m_dynamicParameters.PointSizeRangeMax = m_vulkanCaps.PointSizeRangeMax;
m_dynamicParameters.PointSizeGranularity = m_vulkanCaps.PointSizeGranularity;
m_dynamicParameters.Max3DTextureSize = m_vulkanCaps.Max3DTextureSize;
m_dynamicParameters.MaxArrayTextureLayers = m_vulkanCaps.MaxArrayTextureLayers;
m_dynamicParameters.MaxCubeMapTextureSize = m_vulkanCaps.MaxCubeMapTextureSize;
m_dynamicParameters.MaxFramebufferWidth = m_vulkanCaps.MaxFramebufferWidth;
m_dynamicParameters.MaxFramebufferHeight = m_vulkanCaps.MaxFramebufferHeight;
m_dynamicParameters.MaxFramebufferLayers = m_vulkanCaps.MaxFramebufferLayers;
m_dynamicParameters.MaxRenderbufferSize = m_vulkanCaps.MaxRenderbufferSize;
m_dynamicParameters.MaxTextureSize = m_vulkanCaps.MaxTextureSize;
m_dynamicParameters.MaxColorTextureSamples = m_vulkanCaps.MaxColorTextureSamples;
m_dynamicParameters.MaxDepthTextureSamples = m_vulkanCaps.MaxDepthTextureSamples;
m_dynamicParameters.MaxFramebufferSamples = m_vulkanCaps.MaxFramebufferSamples;
m_dynamicParameters.MaxIntegerSamples = m_vulkanCaps.MaxIntegerSamples;
m_dynamicParameters.MaxSamples = m_vulkanCaps.MaxSamples;
m_dynamicParameters.MaxSampleMaskWords = m_vulkanCaps.MaxSampleMaskWords;
m_dynamicParameters.MaxTextureImageUnits = m_vulkanCaps.MaxTextureImageUnits;
m_dynamicParameters.MaxVertexTextureImageUnits = m_vulkanCaps.MaxVertexTextureImageUnits;
m_dynamicParameters.MaxComputeTextureImageUnits = m_vulkanCaps.MaxComputeTextureImageUnits;
m_dynamicParameters.MaxCombinedTextureImageUnits = m_vulkanCaps.MaxCombinedTextureImageUnits;
m_dynamicParameters.MaxVertexAttribs = m_vulkanCaps.MaxVertexAttribs;
m_dynamicParameters.MaxComputeShaderStorageBlocks = m_vulkanCaps.MaxComputeShaderStorageBlocks;
m_dynamicParameters.MaxCombinedShaderStorageBlocks = m_vulkanCaps.MaxCombinedShaderStorageBlocks;
m_dynamicParameters.MaxComputeUniformBlocks = m_vulkanCaps.MaxComputeUniformBlocks;
m_dynamicParameters.MaxComputeWorkGroupInvocations = m_vulkanCaps.MaxComputeWorkGroupInvocations;
m_dynamicParameters.MaxShaderStorageBufferBindings = m_vulkanCaps.MaxShaderStorageBufferBindings;
m_dynamicParameters.MaxTextureBufferSize = m_vulkanCaps.MaxTextureBufferSize;
m_dynamicParameters.MaxUniformBufferBindings = m_vulkanCaps.MaxUniformBufferBindings;
m_dynamicParameters.MaxUniformBlockSize = m_vulkanCaps.MaxUniformBlockSize;
m_dynamicParameters.MaxImageUnits = m_vulkanCaps.MaxImageUnits;
m_dynamicParameters.MaxCombinedImageUniforms = m_vulkanCaps.MaxCombinedImageUniforms;
m_dynamicParameters.MaxComputeImageUniforms = m_vulkanCaps.MaxComputeImageUniforms;
m_dynamicParameters.MaxDrawBuffers = m_vulkanCaps.MaxDrawBuffers;
m_dynamicParameters.MaxColorAttachments = m_vulkanCaps.MaxColorAttachments;
m_dynamicParameters.MaxClipDistances = m_vulkanCaps.MaxClipDistances;
m_dynamicParameters.MaxViewports = m_vulkanCaps.MaxViewports;
m_dynamicParameters.MaxViewportWidth = m_vulkanCaps.MaxViewportWidth;
m_dynamicParameters.MaxViewportHeight = m_vulkanCaps.MaxViewportHeight;
m_dynamicParameters.ViewportBoundsRangeMin = m_vulkanCaps.ViewportBoundsRangeMin;
m_dynamicParameters.ViewportBoundsRangeMax = m_vulkanCaps.ViewportBoundsRangeMax;
m_dynamicParameters.ViewportSubpixelBits = m_vulkanCaps.ViewportSubpixelBits;
m_dynamicParameters.SupportsWideLines = m_vulkanCaps.SupportsWideLines;
}
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -188,18 +188,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return packet;
}
FrameContext::PresentInfoPacket FrameContext::GetPresentInfo(VkSwapchainKHR swapchain, const Uint32& imageIndex) const {
FrameContext::PresentInfoPacket FrameContext::GetPresentInfo(VkSwapchainKHR swapchain, Uint32 imageIndex) const {
AssertValidSwapchainImageIndex(imageIndex);
PresentInfoPacket packet{};
packet.waitSemaphore = m_swapchainImageRenderFinishedSemaphores[imageIndex];
packet.swapchain = swapchain;
packet.imageIndex = &imageIndex;
packet.imageIndex = imageIndex;
packet.presentInfo.waitSemaphoreCount = 1;
packet.presentInfo.pWaitSemaphores = &packet.waitSemaphore;
packet.presentInfo.swapchainCount = 1;
packet.presentInfo.pSwapchains = &packet.swapchain;
packet.presentInfo.pImageIndices = packet.imageIndex;
packet.presentInfo.pImageIndices = &packet.imageIndex;
packet.presentInfo.pResults = nullptr;
return packet;
}
@@ -212,13 +212,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return result;
}
result = vkResetFences(device, 1, &frame.imageInFlightFence);
result = vkAcquireNextImageKHR(device, swapchain, timeout, frame.imageAvailableSemaphore, acquireFence,
&outImageIndex);
if (result != VK_SUCCESS) {
return result;
}
return vkAcquireNextImageKHR(device, swapchain, timeout, frame.imageAvailableSemaphore, acquireFence,
&outImageIndex);
return vkResetFences(device, 1, &frame.imageInFlightFence);
}
Uint32 FrameContext::GetCurrentFrameIndex() const {
@@ -25,7 +25,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
struct PresentInfoPacket {
VkSemaphore waitSemaphore = VK_NULL_HANDLE;
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
const Uint32* imageIndex = nullptr;
Uint32 imageIndex = 0;
VkPresentInfoKHR presentInfo{VK_STRUCTURE_TYPE_PRESENT_INFO_KHR};
};
@@ -53,7 +53,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Bool TransitionToPresent(VkImage image, VkImageLayout oldLayout,
VkImageLayout presentLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
SubmitInfoPacket GetSubmitInfo(Bool shouldSubmitCommandBuffer, Uint32 swapchainImageIndex) const;
PresentInfoPacket GetPresentInfo(VkSwapchainKHR swapchain, const Uint32& imageIndex) const;
PresentInfoPacket GetPresentInfo(VkSwapchainKHR swapchain, Uint32 imageIndex) const;
VkResult WaitAndAcquireNextImage(VkDevice device, VkSwapchainKHR swapchain, Uint32& outImageIndex,
Uint64 timeout = UINT64_MAX, VkFence acquireFence = VK_NULL_HANDLE);
@@ -39,7 +39,25 @@ namespace MobileGL::MG_Backend::DirectVulkan {
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.depthBiasEnable, sizeof(payload.depthBiasEnable)));
XXHASH_VERIFY(
XXH64_update(m_hashState, &payload.rasterizerDiscardEnable, sizeof(payload.rasterizerDiscardEnable)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.logicOpEnable, sizeof(payload.logicOpEnable)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.stencilTestEnable, sizeof(payload.stencilTestEnable)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.depthCompareOp, sizeof(payload.depthCompareOp)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.logicOp, sizeof(payload.logicOp)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.frontStencilFailOp, sizeof(payload.frontStencilFailOp)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.frontStencilPassOp, sizeof(payload.frontStencilPassOp)));
XXHASH_VERIFY(
XXH64_update(m_hashState, &payload.frontStencilDepthFailOp, sizeof(payload.frontStencilDepthFailOp)));
XXHASH_VERIFY(
XXH64_update(m_hashState, &payload.frontStencilCompareOp, sizeof(payload.frontStencilCompareOp)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.backStencilFailOp, sizeof(payload.backStencilFailOp)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.backStencilPassOp, sizeof(payload.backStencilPassOp)));
XXHASH_VERIFY(
XXH64_update(m_hashState, &payload.backStencilDepthFailOp, sizeof(payload.backStencilDepthFailOp)));
XXHASH_VERIFY(
XXH64_update(m_hashState, &payload.backStencilCompareOp, sizeof(payload.backStencilCompareOp)));
if (payload.colorAttachmentCount > 0) {
XXHASH_VERIFY(XXH64_update(
m_hashState,
@@ -86,7 +104,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
static constexpr VkDynamicState kDynamicStates[] = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR
VK_DYNAMIC_STATE_SCISSOR,
VK_DYNAMIC_STATE_BLEND_CONSTANTS,
VK_DYNAMIC_STATE_DEPTH_BIAS,
VK_DYNAMIC_STATE_LINE_WIDTH,
VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
VK_DYNAMIC_STATE_STENCIL_REFERENCE
};
VkPipelineDynamicStateCreateInfo dynamicState{};
@@ -105,6 +129,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
raster.polygonMode = VK_POLYGON_MODE_FILL;
raster.cullMode = payload.cullMode;
raster.frontFace = payload.frontFace;
raster.depthBiasEnable = payload.depthBiasEnable ? VK_TRUE : VK_FALSE;
raster.rasterizerDiscardEnable = payload.rasterizerDiscardEnable ? VK_TRUE : VK_FALSE;
raster.lineWidth = 1.0f;
VkPipelineMultisampleStateCreateInfo ms{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO};
@@ -115,13 +141,31 @@ namespace MobileGL::MG_Backend::DirectVulkan {
depthStencil.depthWriteEnable = payload.depthWriteEnable ? VK_TRUE : VK_FALSE;
depthStencil.depthCompareOp = payload.depthCompareOp;
depthStencil.depthBoundsTestEnable = VK_FALSE;
depthStencil.stencilTestEnable = VK_FALSE;
depthStencil.stencilTestEnable = payload.stencilTestEnable ? VK_TRUE : VK_FALSE;
if (payload.stencilTestEnable) {
depthStencil.front.failOp = payload.frontStencilFailOp;
depthStencil.front.passOp = payload.frontStencilPassOp;
depthStencil.front.depthFailOp = payload.frontStencilDepthFailOp;
depthStencil.front.compareOp = payload.frontStencilCompareOp;
depthStencil.front.compareMask = 0xffffffffu;
depthStencil.front.writeMask = 0xffffffffu;
depthStencil.front.reference = 0;
depthStencil.back.failOp = payload.backStencilFailOp;
depthStencil.back.passOp = payload.backStencilPassOp;
depthStencil.back.depthFailOp = payload.backStencilDepthFailOp;
depthStencil.back.compareOp = payload.backStencilCompareOp;
depthStencil.back.compareMask = 0xffffffffu;
depthStencil.back.writeMask = 0xffffffffu;
depthStencil.back.reference = 0;
}
Vector<VkPipelineColorBlendAttachmentState> colorAttachments(payload.colorAttachmentCount);
for (Uint32 i = 0; i < payload.colorAttachmentCount; ++i) {
colorAttachments[i] = payload.colorBlendAttachments[i];
}
VkPipelineColorBlendStateCreateInfo blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO};
blend.logicOpEnable = payload.logicOpEnable ? VK_TRUE : VK_FALSE;
blend.logicOp = payload.logicOp;
blend.attachmentCount = payload.colorAttachmentCount;
blend.pAttachments = colorAttachments.empty() ? nullptr : colorAttachments.data();
@@ -32,7 +32,20 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
Bool depthTestEnable = false;
Bool depthWriteEnable = false;
Bool depthBiasEnable = false;
Bool rasterizerDiscardEnable = false;
Bool logicOpEnable = false;
Bool stencilTestEnable = false;
VkCompareOp depthCompareOp = VK_COMPARE_OP_ALWAYS;
VkLogicOp logicOp = VK_LOGIC_OP_COPY;
VkStencilOp frontStencilFailOp = VK_STENCIL_OP_KEEP;
VkStencilOp frontStencilPassOp = VK_STENCIL_OP_KEEP;
VkStencilOp frontStencilDepthFailOp = VK_STENCIL_OP_KEEP;
VkCompareOp frontStencilCompareOp = VK_COMPARE_OP_ALWAYS;
VkStencilOp backStencilFailOp = VK_STENCIL_OP_KEEP;
VkStencilOp backStencilPassOp = VK_STENCIL_OP_KEEP;
VkStencilOp backStencilDepthFailOp = VK_STENCIL_OP_KEEP;
VkCompareOp backStencilCompareOp = VK_COMPARE_OP_ALWAYS;
Array<VkPipelineColorBlendAttachmentState, kMaxColorAttachments> colorBlendAttachments{};
const Vector<VkPipelineShaderStageCreateInfo>* stages = nullptr;
const VkPipelineVertexInputStateCreateInfo* vertexInputState = nullptr;
@@ -153,7 +153,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MGLOG_I("Picked present mode: %s", string_VkPresentModeKHR(presentMode));
const auto& swapchainCaps = swapchainCapabilities.capabilities;
const auto targetImageCount = std::max<Uint32>(minImageCountHint, swapchainCaps.minImageCount);
Uint32 targetImageCount = std::max<Uint32>(minImageCountHint, swapchainCaps.minImageCount);
if (swapchainCaps.maxImageCount != 0) {
targetImageCount = std::min(targetImageCount, swapchainCaps.maxImageCount);
}
MGLOG_I("Set minImageCount = %u", targetImageCount);
MGLOG_I("Swapchain currentTransform = %s",
string_VkSurfaceTransformFlagBitsKHR(swapchainCaps.currentTransform));
@@ -234,11 +237,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// Properly initialize Default FBO here
auto& defaultFBOInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
const Int extentWidth = static_cast<Int>(createInfo.imageExtent.width);
const Int extentHeight = static_cast<Int>(createInfo.imageExtent.height);
const SizeT defaultAttachmentByteSize =
static_cast<SizeT>(createInfo.imageExtent.width) * static_cast<SizeT>(createInfo.imageExtent.height) * 4;
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
{extentWidth, extentHeight, 1},
defaultAttachmentByteSize}); // TODO: 4 is format size
TextureInternalFormat depthFormat = TextureInternalFormat::Depth24Stencil8;
switch (m_depthStencilFormat) {
case VK_FORMAT_D24_UNORM_S8_UINT:
@@ -257,8 +265,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
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
{extentWidth, extentHeight, 1},
defaultAttachmentByteSize}); // TODO: 4 is format size
}
@@ -12,7 +12,19 @@
#include "MG_Util/Converters/MGToStr/TextureEnumConverter.h"
namespace MobileGL::MG_Backend::DirectVulkan {
static SharedPtr<MG_State::GLState::ITextureObject> GetClearableAttachmentTexture(
static Bool IsCubeMapFaceUploadTarget(TextureUploadTarget target) {
return target >= TextureUploadTarget::CubeMapPositiveX &&
target <= TextureUploadTarget::CubeMapNegativeZ;
}
static Uint32 ResolveAttachmentBaseArrayLayer(TextureUploadTarget target) {
if (!IsCubeMapFaceUploadTarget(target)) {
return 0;
}
return static_cast<Uint32>(target) - static_cast<Uint32>(TextureUploadTarget::CubeMapPositiveX);
}
static const MG_State::GLState::FramebufferAttachmentObject* GetClearableAttachment(
const MG_State::GLState::FramebufferObject& drawFbo, FramebufferAttachmentType attachmentType) {
if (attachmentType == FramebufferAttachmentType::None) {
return nullptr;
@@ -23,7 +35,30 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return nullptr;
}
return attachment.GetTexture();
return &attachment;
}
PendingClearKey VkClearManager::MakePendingClearKey(MG_State::GLState::ITextureObject* texture, Uint32 mipLevel,
Uint32 baseArrayLayer, Uint32 layerCount) {
return PendingClearKey {
.texture = texture,
.mipLevel = mipLevel,
.baseArrayLayer = baseArrayLayer,
.layerCount = layerCount,
};
}
PendingClearKey VkClearManager::MakePendingClearKey(
const MG_State::GLState::FramebufferAttachmentObject& attachment) {
MOBILEGL_ASSERT(attachment.IsTexture() && !attachment.IsRenderbuffer(),
"MakePendingClearKey requires a texture framebuffer attachment");
auto* texture = attachment.GetTexture().get();
MOBILEGL_ASSERT(texture != nullptr, "MakePendingClearKey: texture attachment resolved to null");
const Uint32 mipLevel = static_cast<Uint32>(std::max(attachment.GetTextureLevel(), 0));
const TextureUploadTarget uploadTarget = attachment.GetTextureUploadTarget();
const Uint32 baseArrayLayer = ResolveAttachmentBaseArrayLayer(uploadTarget);
const Uint32 layerCount = IsCubeMapFaceUploadTarget(uploadTarget) ? 1u : 1u;
return MakePendingClearKey(texture, mipLevel, baseArrayLayer, layerCount);
}
Bool VkClearManager::Initialize() {
@@ -40,46 +75,46 @@ namespace MobileGL::MG_Backend::DirectVulkan {
auto& drawbufs = drawFbo.GetDrawBuffers();
// This should automatically work on default & offscreen FBO
for (auto drawbuf: drawbufs) {
auto texture = GetClearableAttachmentTexture(drawFbo, drawbuf);
if (!texture) {
const auto* attachment = GetClearableAttachment(drawFbo, drawbuf);
if (!attachment) {
continue;
}
QueueClear({
.mask = GL_COLOR_BUFFER_BIT,
.color = clearPayload.color
}, texture);
}, *attachment);
MGLOG_D("%s: %s (texture %d) - color = (%.2f, %.2f, %.2f, %.2f)", __func__,
MG_Util::ConvertFramebufferAttachmentTypeToString(drawbuf).c_str(),
texture->GetExternalIndex(),
attachment->GetTexture()->GetExternalIndex(),
clearPayload.color[0], clearPayload.color[1], clearPayload.color[2], clearPayload.color[3]);
}
}
if (mask & GL_DEPTH_BUFFER_BIT) {
auto texture = GetClearableAttachmentTexture(drawFbo, FramebufferAttachmentType::Depth);
if (texture) {
const auto* attachment = GetClearableAttachment(drawFbo, FramebufferAttachmentType::Depth);
if (attachment) {
QueueClear({
.mask = GL_DEPTH_BUFFER_BIT,
.depth = clearPayload.depth,
}, texture);
}, *attachment);
MGLOG_D("%s: Depth (texture %d) - depth = (%.2f)", __func__,
texture->GetExternalIndex(), clearPayload.depth);
attachment->GetTexture()->GetExternalIndex(), clearPayload.depth);
}
}
if (mask & GL_STENCIL_BUFFER_BIT) {
auto texture = GetClearableAttachmentTexture(drawFbo, FramebufferAttachmentType::Stencil);
if (texture) {
const auto* attachment = GetClearableAttachment(drawFbo, FramebufferAttachmentType::Stencil);
if (attachment) {
QueueClear({
.mask = GL_STENCIL_BUFFER_BIT,
.stencil = clearPayload.stencil,
}, texture);
}, *attachment);
MGLOG_D("%s: Stencil (texture %d) - stencil = (%u)", __func__,
texture->GetExternalIndex(), clearPayload.stencil);
attachment->GetTexture()->GetExternalIndex(), clearPayload.stencil);
}
}
}
@@ -94,7 +129,35 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return;
auto* pTexture = weakTexturePtr.lock().get();
m_aliveObjects[pTexture] = weakTexturePtr;
auto& pending = m_pendingClears[pTexture];
auto& pending = m_pendingClears[MakePendingClearKey(pTexture)];
pending.mask |= clearPayload.mask;
if (clearPayload.mask & GL_COLOR_BUFFER_BIT) {
pending.color = clearPayload.color;
}
if (clearPayload.mask & GL_DEPTH_BUFFER_BIT) {
pending.depth = clearPayload.depth;
}
if (clearPayload.mask & GL_STENCIL_BUFFER_BIT) {
pending.stencil = clearPayload.stencil;
}
}
void VkClearManager::QueueClear(const ClearAttachmentPayload& clearPayload,
const MG_State::GLState::FramebufferAttachmentObject& attachment) {
if (clearPayload.mask == 0 || !attachment.IsTexture() || attachment.IsRenderbuffer()) {
return;
}
const auto texture = attachment.GetTexture();
if (!texture) {
return;
}
WeakPtr<MG_State::GLState::ITextureObject> weakTexturePtr = texture;
if (weakTexturePtr.expired()) {
return;
}
auto* pTexture = weakTexturePtr.lock().get();
m_aliveObjects[pTexture] = weakTexturePtr;
auto& pending = m_pendingClears[MakePendingClearKey(attachment)];
pending.mask |= clearPayload.mask;
if (clearPayload.mask & GL_COLOR_BUFFER_BIT) {
pending.color = clearPayload.color;
@@ -108,20 +171,40 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
Bool VkClearManager::HasPendingClear(MG_State::GLState::ITextureObject* texture) {
return m_pendingClears.find(texture) != m_pendingClears.end();
if (texture == nullptr) {
return false;
}
return std::any_of(m_pendingClears.begin(), m_pendingClears.end(),
[texture](const auto& item) { return item.first.texture == texture; });
}
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()) {
MGLOG_D("%s: Failed getting pending clear for texture %d", __func__, texture->GetExternalIndex());
Bool VkClearManager::HasPendingClear(const PendingClearKey& key) {
return key.texture != nullptr && m_pendingClears.find(key) != m_pendingClears.end();
}
Bool VkClearManager::HasPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
if (!attachment.IsTexture() || attachment.IsRenderbuffer() || !attachment.GetTexture()) {
return false;
}
return HasPendingClear(MakePendingClearKey(attachment));
}
Bool VkClearManager::GetPendingClear(const PendingClearKey& key, ClearAttachmentPayload& outPayload) {
if (key.texture == nullptr || m_aliveObjects.find(key.texture) == m_aliveObjects.end()) {
return false;
}
auto it = m_pendingClears.find(key);
if (it == m_pendingClears.end()) {
MGLOG_D("%s: Failed getting pending clear for texture %d mip=%u layer=%u count=%u", __func__,
key.texture ? key.texture->GetExternalIndex() : 0, key.mipLevel, key.baseArrayLayer, key.layerCount);
return false;
}
outPayload = m_pendingClears[texture];
MGLOG_D("%s: Got pending clear for texture %d (%s), mask=0x%x clear value: color = (%.2f, %.2f, %.2f, %.2f), depth = (%.2f), stencil = (%u)", __func__,
texture->GetExternalIndex(),
MG_Util::ConvertTextureInternalFormatToString(texture->GetFormat()).c_str(),
outPayload = it->second;
MGLOG_D("%s: Got pending clear for texture %d (%s), mip=%u layer=%u count=%u mask=0x%x clear value: color = (%.2f, %.2f, %.2f, %.2f), depth = (%.2f), stencil = (%u)", __func__,
key.texture->GetExternalIndex(),
MG_Util::ConvertTextureInternalFormatToString(key.texture->GetFormat()).c_str(),
key.mipLevel, key.baseArrayLayer, key.layerCount,
static_cast<Uint32>(outPayload.mask),
outPayload.color[0], outPayload.color[1], outPayload.color[2], outPayload.color[3],
outPayload.depth,
@@ -129,10 +212,59 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return true;
}
Bool VkClearManager::GetPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment,
ClearAttachmentPayload& outPayload) {
if (!attachment.IsTexture() || attachment.IsRenderbuffer() || !attachment.GetTexture()) {
MGLOG_D("%s: Failed getting pending clear for non-texture framebuffer attachment", __func__);
return false;
}
return GetPendingClear(MakePendingClearKey(attachment), outPayload);
}
Bool VkClearManager::GetPendingClears(MG_State::GLState::ITextureObject* texture,
Vector<PendingClearEntry>& outEntries) {
outEntries.clear();
if (texture == nullptr || m_aliveObjects.find(texture) == m_aliveObjects.end()) {
return false;
}
for (const auto& [key, payload] : m_pendingClears) {
if (key.texture != texture) {
continue;
}
outEntries.emplace_back(PendingClearEntry{.key = key, .payload = payload});
}
return !outEntries.empty();
}
void VkClearManager::PopPendingClear(MG_State::GLState::ITextureObject* texture) {
MGLOG_D("%s: Pop pending clear for texture %d", __func__, texture->GetExternalIndex());
if (texture == nullptr) {
return;
}
MGLOG_D("%s: Pop all pending clears for texture %d", __func__, texture->GetExternalIndex());
m_aliveObjects.erase(texture);
m_pendingClears.erase(texture);
for (auto it = m_pendingClears.begin(); it != m_pendingClears.end();) {
if (it->first.texture == texture) {
it = m_pendingClears.erase(it);
} else {
++it;
}
}
}
void VkClearManager::PopPendingClear(const PendingClearKey& key) {
if (key.texture == nullptr) {
return;
}
MGLOG_D("%s: Pop pending clear for texture %d mip=%u layer=%u count=%u", __func__,
key.texture->GetExternalIndex(), key.mipLevel, key.baseArrayLayer, key.layerCount);
m_pendingClears.erase(key);
}
void VkClearManager::PopPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
if (!attachment.IsTexture() || attachment.IsRenderbuffer() || !attachment.GetTexture()) {
return;
}
PopPendingClear(MakePendingClearKey(attachment));
}
SizeT VkClearManager::CollectGarbage() {
@@ -145,7 +277,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
for (auto it = m_aliveObjects.begin(); it != m_aliveObjects.end();) {
auto current = it++;
if (current->second.expired()) {
m_pendingClears.erase(current->first);
for (auto clearIt = m_pendingClears.begin(); clearIt != m_pendingClears.end();) {
if (clearIt->first.texture == current->first) {
clearIt = m_pendingClears.erase(clearIt);
} else {
++clearIt;
}
}
m_aliveObjects.erase(current);
++count;
}
@@ -29,8 +29,43 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Uint32 stencil = 0;
};
struct PendingClearKey {
MG_State::GLState::ITextureObject* texture = nullptr;
Uint32 mipLevel = 0;
Uint32 baseArrayLayer = 0;
Uint32 layerCount = 1;
Bool operator==(const PendingClearKey& other) const {
return texture == other.texture && mipLevel == other.mipLevel &&
baseArrayLayer == other.baseArrayLayer && layerCount == other.layerCount;
}
};
struct PendingClearEntry {
PendingClearKey key{};
ClearAttachmentPayload payload{};
};
struct PendingClearKeyHash {
SizeT operator()(const PendingClearKey& key) const {
const SizeT textureHash = std::hash<MG_State::GLState::ITextureObject*>{}(key.texture);
const SizeT mipHash = std::hash<Uint32>{}(key.mipLevel);
const SizeT layerHash = std::hash<Uint32>{}(key.baseArrayLayer);
const SizeT layerCountHash = std::hash<Uint32>{}(key.layerCount);
SizeT hash = textureHash;
hash ^= mipHash + 0x9e3779b9u + (hash << 6) + (hash >> 2);
hash ^= layerHash + 0x9e3779b9u + (hash << 6) + (hash >> 2);
hash ^= layerCountHash + 0x9e3779b9u + (hash << 6) + (hash >> 2);
return hash;
}
};
class VkClearManager {
public:
static PendingClearKey MakePendingClearKey(const MG_State::GLState::FramebufferAttachmentObject& attachment);
static PendingClearKey MakePendingClearKey(MG_State::GLState::ITextureObject* texture, Uint32 mipLevel = 0,
Uint32 baseArrayLayer = 0, Uint32 layerCount = 1);
Bool Initialize();
void Shutdown();
@@ -38,13 +73,22 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void QueueClear(
const ClearAttachmentPayload& clearPayload,
const SharedPtr<MG_State::GLState::ITextureObject>& texture);
void QueueClear(const ClearAttachmentPayload& clearPayload,
const MG_State::GLState::FramebufferAttachmentObject& attachment);
Bool HasPendingClear(MG_State::GLState::ITextureObject* texture);
Bool GetPendingClear(MG_State::GLState::ITextureObject* texture, ClearAttachmentPayload& outPayload);
Bool HasPendingClear(const PendingClearKey& key);
Bool HasPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment);
Bool GetPendingClear(const PendingClearKey& key, ClearAttachmentPayload& outPayload);
Bool GetPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment,
ClearAttachmentPayload& outPayload);
Bool GetPendingClears(MG_State::GLState::ITextureObject* texture, Vector<PendingClearEntry>& outEntries);
void PopPendingClear(MG_State::GLState::ITextureObject* texture);
void PopPendingClear(const PendingClearKey& key);
void PopPendingClear(const MG_State::GLState::FramebufferAttachmentObject& attachment);
SizeT CollectGarbage();
private:
Uint8 m_gcCounter = 0;
UnorderedMap<MG_State::GLState::ITextureObject*, ClearAttachmentPayload> m_pendingClears;
UnorderedMap<PendingClearKey, ClearAttachmentPayload, PendingClearKeyHash> m_pendingClears;
UnorderedMap<MG_State::GLState::ITextureObject*, WeakPtr<MG_State::GLState::ITextureObject>> m_aliveObjects;
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -22,6 +22,32 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return requestedAlpha;
}
static Bool IsCubeMapFaceUploadTarget(TextureUploadTarget target) {
return target >= TextureUploadTarget::CubeMapPositiveX &&
target <= TextureUploadTarget::CubeMapNegativeZ;
}
static Uint32 ResolveAttachmentBaseArrayLayer(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
const TextureUploadTarget uploadTarget = attachment.GetTextureUploadTarget();
if (!IsCubeMapFaceUploadTarget(uploadTarget)) {
return 0;
}
return static_cast<Uint32>(uploadTarget) - static_cast<Uint32>(TextureUploadTarget::CubeMapPositiveX);
}
static Uint32 ResolveAttachmentLayerCount(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
static_cast<void>(attachment);
return 1u;
}
static VkImageViewType ResolveAttachmentViewType(
const MG_State::GLState::FramebufferAttachmentObject& attachment,
const VkTextureManager::TextureResource& resource) {
return IsCubeMapFaceUploadTarget(attachment.GetTextureUploadTarget()) ?
VK_IMAGE_VIEW_TYPE_2D :
resource.viewType;
}
static MG_State::GLState::ITextureObject* ResolveCompleteColorAttachmentTexture(
const MG_State::GLState::FramebufferObject& fbo,
FramebufferAttachmentType attachmentType,
@@ -79,6 +105,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
void VkRenderPassManager::Shutdown() {
m_renderPasses.clear();
RenderPassEntry::s_textureResourcesScratch.clear();
s_activeRenderPass = {};
s_hasActiveRenderPass = false;
}
VkRenderPassManager::HashType VkRenderPassManager::ComputeHash(
@@ -117,6 +147,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
if (att.IsTexture()) {
const Int textureLevel = att.GetTextureLevel();
XXHASH_VERIFY(XXH64_update(m_hashState, &textureLevel, sizeof(textureLevel)));
const TextureUploadTarget textureUploadTarget = att.GetTextureUploadTarget();
XXHASH_VERIFY(XXH64_update(m_hashState, &textureUploadTarget, sizeof(textureUploadTarget)));
Uint64 imageIdentity = 0;
auto* texture = att.GetTexture().get();
@@ -129,11 +161,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
if (includePendingClear && att.IsTexture()) {
auto* texture = att.GetTexture().get();
auto hasClear = m_clearManager.HasPendingClear(texture);
const auto pendingClearKey = VkClearManager::MakePendingClearKey(att);
auto hasClear = m_clearManager.HasPendingClear(pendingClearKey);
XXHASH_VERIFY(XXH64_update(m_hashState, &hasClear, sizeof(hasClear)));
if (hasClear) {
ClearAttachmentPayload clearPayload{};
Bool hasPayload = m_clearManager.GetPendingClear(texture, clearPayload);
Bool hasPayload = m_clearManager.GetPendingClear(pendingClearKey, clearPayload);
XXHASH_VERIFY(XXH64_update(m_hashState, &hasPayload, sizeof(hasPayload)));
if (hasPayload) {
XXHASH_VERIFY(XXH64_update(m_hashState, &clearPayload.mask, sizeof(clearPayload.mask)));
@@ -180,18 +213,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
const auto& att = fbo.GetAttachment(attachment);
if (att.IsTexture() && m_clearManager.HasPendingClear(att.GetTexture().get())) {
if (att.IsTexture() && m_clearManager.HasPendingClear(att)) {
return true;
}
}
const auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth);
if (depthAtt.IsTexture() && m_clearManager.HasPendingClear(depthAtt.GetTexture().get())) {
if (depthAtt.IsTexture() && m_clearManager.HasPendingClear(depthAtt)) {
return true;
}
const auto& stencilAtt = fbo.GetAttachment(FramebufferAttachmentType::Stencil);
if (stencilAtt.IsTexture() && m_clearManager.HasPendingClear(stencilAtt.GetTexture().get())) {
if (stencilAtt.IsTexture() && m_clearManager.HasPendingClear(stencilAtt)) {
return true;
}
@@ -266,7 +299,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
texture2d->GetFormat());
desc.samples = VK_SAMPLE_COUNT_1_BIT;
ClearAttachmentPayload clearPayload{};
Bool hasClear = m_clearManager.GetPendingClear(texture, clearPayload);
Bool hasClear = m_clearManager.GetPendingClear(att, clearPayload);
VkImageLayout trackedColorLayout = VK_IMAGE_LAYOUT_UNDEFINED;
desc.loadOp = hasClear ?
VK_ATTACHMENT_LOAD_OP_CLEAR :
@@ -280,7 +313,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
if (hasClear) {
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
.attachmentIndex = attachmentIndex,
.texture = texture
.key = VkClearManager::MakePendingClearKey(att)
});
}
if (width == 0)
@@ -313,7 +346,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
.textureMipLevel = attachmentMipLevel,
.finalLayout = desc.finalLayout,
});
attachmentViews.emplace_back(m_textureManager.GetOrCreateViewAtMipLevel(*texture, attachmentMipLevel));
const Uint32 baseArrayLayer = ResolveAttachmentBaseArrayLayer(att);
const Uint32 layerCount = ResolveAttachmentLayerCount(att);
const VkImageViewType attachmentViewType = ResolveAttachmentViewType(att, *textureResource);
attachmentViews.emplace_back(
m_textureManager.GetOrCreateAttachmentViewAtMipLevel(
*texture, attachmentMipLevel, baseArrayLayer, layerCount, attachmentViewType));
MOBILEGL_ASSERT(attachmentViews.back() != VK_NULL_HANDLE,
"GetOrCreateRenderPass: GetOrCreateAttachmentView failed at color attachment %d", i);
}
@@ -340,19 +378,35 @@ namespace MobileGL::MG_Backend::DirectVulkan {
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
// Depth attachment description
// Depth/stencil attachment description
auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth);
auto& stencilAtt = fbo.GetAttachment(FramebufferAttachmentType::Stencil);
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 attachmentMipLevel = static_cast<Uint32>(std::max(depthAtt.GetTextureLevel(), 0));
const auto isUsableDepthStencilAttachment = [](const auto& attachment) {
return attachment.IsComplete() && attachment.IsTexture();
};
const auto* selectedDepthStencilAttachment = isUsableDepthStencilAttachment(depthAtt) ? &depthAtt :
(isUsableDepthStencilAttachment(stencilAtt) ? &stencilAtt : nullptr);
const Bool hasDistinctDepthAndStencilAttachments =
isUsableDepthStencilAttachment(depthAtt) && isUsableDepthStencilAttachment(stencilAtt) &&
(depthAtt.GetTexture().get() != stencilAtt.GetTexture().get() ||
depthAtt.GetTextureUploadTarget() != stencilAtt.GetTextureUploadTarget() ||
depthAtt.GetTextureLevel() != stencilAtt.GetTextureLevel());
if (hasDistinctDepthAndStencilAttachments) {
MGLOG_E("GetOrCreateRenderPass: separate depth/stencil attachments are not supported yet; using the depth attachment and ignoring the standalone stencil attachment for framebuffer %u",
fbo.GetExternalIndex());
}
if (selectedDepthStencilAttachment != nullptr) {
auto& texture = *selectedDepthStencilAttachment->GetTexture();
const Uint32 attachmentMipLevel =
static_cast<Uint32>(std::max(selectedDepthStencilAttachment->GetTextureLevel(), 0));
const Uint32 depthAttachmentIndex = static_cast<Uint32>(attachmentDescriptions.size());
ClearAttachmentPayload clearPayload{};
Bool hasClear = m_clearManager.GetPendingClear(&texture, clearPayload);
Bool hasClear = m_clearManager.GetPendingClear(*selectedDepthStencilAttachment, clearPayload);
Bool clearDepth = hasClear && (clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0;
Bool clearStencil = hasClear && (clearPayload.mask & GL_STENCIL_BUFFER_BIT) != 0;
VkImageLayout trackedDepthLayout = isDefaultFbo ?
@@ -396,7 +450,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
if (hasClear) {
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
.attachmentIndex = depthAttachmentIndex,
.texture = &texture
.key = VkClearManager::MakePendingClearKey(*selectedDepthStencilAttachment)
});
}
if (isDefaultFbo) {
@@ -417,12 +471,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
.finalLayout = depthAttachmentDescription.finalLayout,
});
textureResources.emplace_back(depthTextureResource);
attachmentViews.emplace_back(m_textureManager.GetOrCreateViewAtMipLevel(texture, attachmentMipLevel));
const Uint32 baseArrayLayer = ResolveAttachmentBaseArrayLayer(*selectedDepthStencilAttachment);
const Uint32 layerCount = ResolveAttachmentLayerCount(*selectedDepthStencilAttachment);
const VkImageViewType attachmentViewType =
ResolveAttachmentViewType(*selectedDepthStencilAttachment, *depthTextureResource);
attachmentViews.emplace_back(
m_textureManager.GetOrCreateAttachmentViewAtMipLevel(
texture, attachmentMipLevel, baseArrayLayer, layerCount, attachmentViewType));
MOBILEGL_ASSERT(attachmentViews.back() != VK_NULL_HANDLE,
"GetOrCreateRenderPass: GetOrCreateAttachmentView failed at depth attachment");
if (width == 0 || height == 0) {
width = depthAtt.GetSize().x();
height = depthAtt.GetSize().y();
width = selectedDepthStencilAttachment->GetSize().x();
height = selectedDepthStencilAttachment->GetSize().y();
}
}
attachmentDescriptions.emplace_back(depthAttachmentDescription);
@@ -439,7 +499,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
subpassDesc.colorAttachmentCount = colorAttachmentRefs.size();
subpassDesc.pColorAttachments = colorAttachmentRefs.data();
subpassDesc.pResolveAttachments = nullptr;
subpassDesc.pDepthStencilAttachment = depthAtt.IsComplete() ? &depthAttachmentRef : VK_NULL_HANDLE;
subpassDesc.pDepthStencilAttachment = hasDepthStencilAttachment ? &depthAttachmentRef : VK_NULL_HANDLE;
subpassDesc.preserveAttachmentCount = 0;
subpassDesc.pPreserveAttachments = nullptr;
@@ -512,11 +572,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
clearValue.depthStencil = {1.0f, 0};
}
for (const auto& pending: renderPassEntry.pendingClearAttachments) {
if (!pending.texture || pending.attachmentIndex >= clearValues.size()) {
if (pending.key.texture == nullptr || pending.attachmentIndex >= clearValues.size()) {
continue;
}
ClearAttachmentPayload clearPayload{};
if (!s_clearManager->GetPendingClear(pending.texture, clearPayload)) {
if (!s_clearManager->GetPendingClear(pending.key, clearPayload)) {
continue;
}
if ((clearPayload.mask & GL_COLOR_BUFFER_BIT) != 0) {
@@ -524,7 +584,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
clearPayload.color.x(),
clearPayload.color.y(),
clearPayload.color.z(),
ResolveColorClearAlpha(pending.texture, clearPayload.color.w())
ResolveColorClearAlpha(pending.key.texture, clearPayload.color.w())
};
}
if ((clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
@@ -540,7 +600,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
for (const auto& pending: renderPassEntry.pendingClearAttachments) {
s_clearManager->PopPendingClear(pending.texture);
s_clearManager->PopPendingClear(pending.key);
}
s_activeRenderPass.hash = renderPassEntry.hash;
s_activeRenderPass.compatibilityHash = renderPassEntry.compatibilityHash;
@@ -26,7 +26,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
struct PendingClearAttachmentInfo {
Uint32 attachmentIndex = 0;
MG_State::GLState::ITextureObject* texture = nullptr;
PendingClearKey key{};
};
struct TrackedAttachmentLayoutInfo {
@@ -71,6 +71,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
}
static VkImageLayout ResolveSampledReadOnlyLayout(VkImageAspectFlags aspectMask) {
return (aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
static void GetImageTransitionSourceState(VkImageLayout oldLayout,
VkPipelineStageFlags& outSrcStageMask,
VkAccessFlags& outSrcAccessMask) {
@@ -594,7 +600,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
perMipView = CreateImageView(resource->image, resource->format, resource->aspect, resource->viewType,
mipLevel, 1, resource->arrayLayers);
mipLevel, 1, 0, resource->arrayLayers);
if (perMipView == VK_NULL_HANDLE) {
MGLOG_D("%s: CreateImageView failed for textureId=%d mipLevel=%u", __func__, texture.GetExternalIndex(), mipLevel);
return VK_NULL_HANDLE;
@@ -603,6 +609,53 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return perMipView;
}
VkImageView VkTextureManager::GetOrCreateAttachmentViewAtMipLevel(MG_State::GLState::ITextureObject& texture,
Uint32 mipLevel, Uint32 baseArrayLayer,
Uint32 layerCount,
VkImageViewType viewType) {
TextureResource* resource = SyncTextureAndGetDescriptor(texture);
if (resource == nullptr || resource->image == VK_NULL_HANDLE || mipLevel >= resource->mipLevels) {
return VK_NULL_HANDLE;
}
if (layerCount == 0 || baseArrayLayer >= resource->arrayLayers ||
baseArrayLayer + layerCount > resource->arrayLayers) {
MGLOG_D("%s: invalid layer span [%u, %u) for textureId=%d arrayLayers=%u",
__func__, baseArrayLayer, baseArrayLayer + layerCount, texture.GetExternalIndex(),
resource->arrayLayers);
return VK_NULL_HANDLE;
}
if (baseArrayLayer == 0 && layerCount == resource->arrayLayers && viewType == resource->viewType) {
return GetOrCreateViewAtMipLevel(texture, mipLevel);
}
const TextureResource::AttachmentViewKey key{
.mipLevel = mipLevel,
.baseArrayLayer = baseArrayLayer,
.layerCount = layerCount,
.viewType = viewType,
};
auto it = resource->attachmentViews.find(key);
if (it == resource->attachmentViews.end()) {
it = resource->attachmentViews.emplace(key, VK_NULL_HANDLE).first;
}
VkImageView& attachmentView = it->second;
if (attachmentView != VK_NULL_HANDLE) {
return attachmentView;
}
attachmentView = CreateImageView(resource->image, resource->format, resource->aspect, viewType,
mipLevel, 1, baseArrayLayer, layerCount);
if (attachmentView == VK_NULL_HANDLE) {
MGLOG_D("%s: CreateImageView failed for textureId=%d mipLevel=%u baseArrayLayer=%u layerCount=%u viewType=%d",
__func__, texture.GetExternalIndex(), mipLevel, baseArrayLayer, layerCount, static_cast<Int>(viewType));
resource->attachmentViews.erase(it);
return VK_NULL_HANDLE;
}
return attachmentView;
}
VkImageView VkTextureManager::GetOrCreateSampledViewAtMipLevel(MG_State::GLState::ITextureObject& texture,
Uint32 mipLevel) {
TextureResource* resource = SyncTextureAndGetDescriptor(texture);
@@ -622,7 +675,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const TextureFormatInfo formatInfo = ResolveTextureFormatInfo(texture.GetFormat());
const VkComponentMapping sampledComponents = ResolveSampledViewComponents(texture, formatInfo);
perMipSampledView = CreateImageView(resource->image, resource->format, resource->aspect, resource->viewType,
mipLevel, 1, resource->arrayLayers, &sampledComponents);
mipLevel, 1, 0, resource->arrayLayers, &sampledComponents);
if (perMipSampledView == VK_NULL_HANDLE) {
MGLOG_D("%s: CreateImageView failed for textureId=%d mipLevel=%u", __func__, texture.GetExternalIndex(),
mipLevel);
@@ -1109,7 +1162,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const TextureFormatInfo formatInfo = ResolveTextureFormatInfo(texture.GetFormat());
const VkComponentMapping sampledComponents = ResolveSampledViewComponents(texture, formatInfo);
resource.fullView = CreateImageView(resource.image, resource.format, resource.aspect, resource.viewType,
baseMipLevel, levelCount, resource.arrayLayers, &sampledComponents);
baseMipLevel, levelCount, 0, resource.arrayLayers, &sampledComponents);
if (resource.fullView == VK_NULL_HANDLE) {
return false;
}
@@ -1122,6 +1175,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkImageView VkTextureManager::CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspect,
VkImageViewType viewType, Uint32 baseMipLevel, Uint32 levelCount,
Uint32 baseArrayLayer,
Uint32 layerCount,
const VkComponentMapping* components) const {
VkImageViewCreateInfo viewInfo{};
@@ -1136,7 +1190,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
viewInfo.subresourceRange.aspectMask = aspect;
viewInfo.subresourceRange.baseMipLevel = baseMipLevel;
viewInfo.subresourceRange.levelCount = levelCount;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.baseArrayLayer = baseArrayLayer;
viewInfo.subresourceRange.layerCount = layerCount;
VkImageView view = VK_NULL_HANDLE;
@@ -1293,17 +1347,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
1, &copy);
}
const VkImageLayout finalLayout = ResolveSampledReadOnlyLayout(aspectMask);
VkImageLayout uploadLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
ok = TransitionImageLayout(commandBuffer, outResource.image,
uploadLayout,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
kGraphicsSampledReadStages,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT,
aspectMask, 0, outResource.mipLevels, outResource.arrayLayers);
MOBILEGL_ASSERT(ok, "TransitionImageLayout to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL failed");
outResource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
uploadLayout,
finalLayout,
VK_PIPELINE_STAGE_TRANSFER_BIT,
kGraphicsSampledReadStages,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT,
aspectMask, 0, outResource.mipLevels, outResource.arrayLayers);
MOBILEGL_ASSERT(ok, "TransitionImageLayout to sampled read-only layout failed");
outResource.layout = finalLayout;
VK_VERIFY(vkEndCommandBuffer(commandBuffer), "vkEndCommandBuffer(texture)");
@@ -1331,7 +1386,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
for (const auto& item : uploadItems) {
mipmapTexture.MarkStorageDirty(item.target, item.level, false);
}
outResource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
outResource.layout = finalLayout;
return true;
}
@@ -30,11 +30,37 @@ public:
};
struct TextureResource {
struct AttachmentViewKey {
Uint32 mipLevel = 0;
Uint32 baseArrayLayer = 0;
Uint32 layerCount = 1;
VkImageViewType viewType = VK_IMAGE_VIEW_TYPE_2D;
Bool operator==(const AttachmentViewKey& other) const {
return mipLevel == other.mipLevel &&
baseArrayLayer == other.baseArrayLayer &&
layerCount == other.layerCount &&
viewType == other.viewType;
}
};
struct AttachmentViewKeyHash {
SizeT operator()(const AttachmentViewKey& key) const {
SizeT hash = std::hash<Uint32>{}(key.mipLevel);
hash ^= std::hash<Uint32>{}(key.baseArrayLayer) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
hash ^= std::hash<Uint32>{}(key.layerCount) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
hash ^= std::hash<Uint32>{}(static_cast<Uint32>(key.viewType)) +
0x9e3779b9u + (hash << 6) + (hash >> 2);
return hash;
}
};
VkImage image = VK_NULL_HANDLE;
VmaAllocation allocation = nullptr;
VkImageView fullView = VK_NULL_HANDLE;
Vector<VkImageView> perMipViews;
Vector<VkImageView> perMipSampledViews;
UnorderedMap<AttachmentViewKey, VkImageView, AttachmentViewKeyHash> attachmentViews;
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
VkExtent2D extent = {0, 0};
Uint32 depth = 1;
@@ -55,6 +81,7 @@ public:
std::swap(this->fullView, that.fullView);
std::swap(this->perMipViews, that.perMipViews);
std::swap(this->perMipSampledViews, that.perMipSampledViews);
std::swap(this->attachmentViews, that.attachmentViews);
std::swap(this->layout, that.layout);
std::swap(this->extent, that.extent);
std::swap(this->depth, that.depth);
@@ -82,12 +109,18 @@ public:
vkDestroyImageView(s_device, sampledView, nullptr);
}
}
for (const auto& [_, attachmentView] : attachmentViews) {
if (attachmentView != VK_NULL_HANDLE) {
vkDestroyImageView(s_device, attachmentView, nullptr);
}
}
if (image != VK_NULL_HANDLE && allocation != nullptr) {
vmaDestroyImage(s_allocator, image, allocation);
}
fullView = VK_NULL_HANDLE;
perMipViews.clear();
perMipSampledViews.clear();
attachmentViews.clear();
image = VK_NULL_HANDLE;
allocation = nullptr;
layout = VK_IMAGE_LAYOUT_UNDEFINED;
@@ -118,6 +151,9 @@ public:
TextureResource* SyncTextureAndGetDescriptor(
MG_State::GLState::ITextureObject& texture);
VkImageView GetOrCreateViewAtMipLevel(MG_State::GLState::ITextureObject& texture, Uint32 mipLevel);
VkImageView GetOrCreateAttachmentViewAtMipLevel(MG_State::GLState::ITextureObject& texture, Uint32 mipLevel,
Uint32 baseArrayLayer, Uint32 layerCount,
VkImageViewType viewType);
VkImageView GetOrCreateSampledViewAtMipLevel(MG_State::GLState::ITextureObject& texture, Uint32 mipLevel);
void UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout);
void UpdateTrackedImageLayoutAfterAttachmentWrite(VkCommandBuffer commandBuffer,
@@ -146,6 +182,7 @@ private:
Bool SyncTextureViews(const MG_State::GLState::ITextureObject& texture, TextureResource& resource);
VkImageView CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspect,
VkImageViewType viewType, Uint32 baseMipLevel, Uint32 levelCount,
Uint32 baseArrayLayer,
Uint32 layerCount,
const VkComponentMapping* components = nullptr) const;
Bool UploadDirtyMipLevels(MG_State::GLState::TextureObjectMipmap &mipmapTexture,
@@ -90,6 +90,78 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return requestedAlpha;
}
static void ApplyGLViewportState(VkCommandBuffer commandBuffer, const IntVec2& fallbackExtent) {
const IntVec4& viewportState = MG_State::pGLContext->GetViewport();
const FloatVec2& depthRange = MG_State::pGLContext->GetDepthRange();
VkViewport viewport{};
viewport.x = static_cast<float>(viewportState.x());
viewport.y = static_cast<float>(viewportState.y());
viewport.width =
static_cast<float>(viewportState.z() > 0 ? viewportState.z() : fallbackExtent.x());
viewport.height =
static_cast<float>(viewportState.w() > 0 ? viewportState.w() : fallbackExtent.y());
viewport.minDepth = depthRange.x();
viewport.maxDepth = depthRange.y();
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
}
static void ApplyBlendConstants(VkCommandBuffer commandBuffer) {
const FloatVec4& blendColor = MG_State::pGLContext->GetBlendColor();
const float blendConstants[4] = {
blendColor.x(),
blendColor.y(),
blendColor.z(),
blendColor.w(),
};
vkCmdSetBlendConstants(commandBuffer, blendConstants);
}
static Bool DrawModeUsesPolygonFill(GLenum mode) {
switch (mode) {
case GL_TRIANGLES:
case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN:
return true;
default:
return false;
}
}
static void ApplyPolygonOffsetState(VkCommandBuffer commandBuffer) {
vkCmdSetDepthBias(commandBuffer, MG_State::pGLContext->GetPolygonOffsetUnits(), 0.0f,
MG_State::pGLContext->GetPolygonOffsetFactor());
}
static void ApplyLineWidthState(VkCommandBuffer commandBuffer) {
Float lineWidth = MG_State::pGLContext->GetLineWidth();
if (MG_Backend::pActiveBackendObject != nullptr) {
const auto& dynamicParameters = MG_Backend::pActiveBackendObject->GetDynamicParameters();
const Float minLineWidth = dynamicParameters.AliasedLineWidthRangeMin;
const Float maxLineWidth = dynamicParameters.AliasedLineWidthRangeMax;
if (lineWidth < minLineWidth) {
lineWidth = minLineWidth;
} else if (lineWidth > maxLineWidth) {
lineWidth = maxLineWidth;
}
}
vkCmdSetLineWidth(commandBuffer, lineWidth);
}
static void ApplyStencilState(VkCommandBuffer commandBuffer) {
const StencilFaceState& frontStencil = MG_State::pGLContext->GetStencilState(StencilFace::Front);
const StencilFaceState& backStencil = MG_State::pGLContext->GetStencilState(StencilFace::Back);
vkCmdSetStencilCompareMask(commandBuffer, VK_STENCIL_FACE_FRONT_BIT, frontStencil.ValueMask);
vkCmdSetStencilCompareMask(commandBuffer, VK_STENCIL_FACE_BACK_BIT, backStencil.ValueMask);
vkCmdSetStencilWriteMask(commandBuffer, VK_STENCIL_FACE_FRONT_BIT, frontStencil.WriteMask);
vkCmdSetStencilWriteMask(commandBuffer, VK_STENCIL_FACE_BACK_BIT, backStencil.WriteMask);
vkCmdSetStencilReference(commandBuffer, VK_STENCIL_FACE_FRONT_BIT,
static_cast<Uint32>(std::max(frontStencil.Ref, 0)));
vkCmdSetStencilReference(commandBuffer, VK_STENCIL_FACE_BACK_BIT,
static_cast<Uint32>(std::max(backStencil.Ref, 0)));
}
enum class NumericDomain {
Unknown,
FloatLike,
@@ -632,6 +704,51 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MG_State::pGLContext->RecordError(code, MakeUnique<GenericErrorInfo>("DirectVulkan", func, message));
}
static Bool HasDistinctCompleteDepthStencilTextureAttachments(
const MG_State::GLState::FramebufferObject& framebufferObject) {
if (framebufferObject.GetExternalIndex() == 0) {
return false;
}
const auto& depthAttachment = framebufferObject.GetAttachment(FramebufferAttachmentType::Depth);
const auto& stencilAttachment = framebufferObject.GetAttachment(FramebufferAttachmentType::Stencil);
if (!depthAttachment.IsComplete() || !stencilAttachment.IsComplete() ||
!depthAttachment.IsTexture() || !stencilAttachment.IsTexture()) {
return false;
}
return depthAttachment.GetTexture().get() != stencilAttachment.GetTexture().get() ||
depthAttachment.GetTextureUploadTarget() != stencilAttachment.GetTextureUploadTarget() ||
depthAttachment.GetTextureLevel() != stencilAttachment.GetTextureLevel();
}
static Bool HasCompleteRenderbufferAttachment(const MG_State::GLState::FramebufferObject& framebufferObject) {
if (framebufferObject.GetExternalIndex() == 0) {
return false;
}
for (const auto& attachment : framebufferObject.GetAllAttachmentObjects()) {
if (attachment.IsRenderbuffer() && attachment.IsComplete()) {
return true;
}
}
return false;
}
static Bool IsUnsupportedFramebufferForDirectVulkan(
const MG_State::GLState::FramebufferObject& framebufferObject) {
return HasDistinctCompleteDepthStencilTextureAttachments(framebufferObject) ||
HasCompleteRenderbufferAttachment(framebufferObject);
}
static void RecordUnsupportedFramebufferError(const char* func) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidFramebufferOperation,
MakeUnique<GenericErrorInfo>(
"DirectVulkan", func,
"DirectVulkan does not support this non-default framebuffer configuration."));
}
static Bool IsValidSampledImageLayout(VkImageLayout layout) {
switch (layout) {
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
@@ -778,6 +895,19 @@ void main() {
: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
static Bool IsCubeMapFaceUploadTarget(TextureUploadTarget target) {
return target >= TextureUploadTarget::CubeMapPositiveX &&
target <= TextureUploadTarget::CubeMapNegativeZ;
}
static Uint32 ResolveAttachmentBaseArrayLayer(const MG_State::GLState::FramebufferAttachmentObject& attachment) {
const TextureUploadTarget uploadTarget = attachment.GetTextureUploadTarget();
if (!IsCubeMapFaceUploadTarget(uploadTarget)) {
return 0;
}
return static_cast<Uint32>(uploadTarget) - static_cast<Uint32>(TextureUploadTarget::CubeMapPositiveX);
}
enum class BlitSurfaceTransform : Uint32 {
Identity = 0,
Rotate90 = 1,
@@ -792,6 +922,8 @@ void main() {
IntVec2 extent = {0, 0};
Uint32 mipLevel = 0;
Uint32 mipLevelCount = 1;
Uint32 baseArrayLayer = 0;
Uint32 layerCount = 1;
const char* label = nullptr;
};
@@ -968,6 +1100,8 @@ void main() {
outBinding.extent = {static_cast<Int>(extent.width), static_cast<Int>(extent.height)};
outBinding.mipLevel = 0;
outBinding.mipLevelCount = 1;
outBinding.baseArrayLayer = 0;
outBinding.layerCount = 1;
return true;
}
@@ -990,6 +1124,8 @@ void main() {
outBinding.extent = {attachmentExtent.x(), attachmentExtent.y()};
outBinding.mipLevel = static_cast<Uint32>(std::max(attachment.GetTextureLevel(), 0));
outBinding.mipLevelCount = resource->mipLevels;
outBinding.baseArrayLayer = ResolveAttachmentBaseArrayLayer(attachment);
outBinding.layerCount = 1;
return true;
}
@@ -1013,6 +1149,8 @@ void main() {
outBinding.extent = {static_cast<Int>(extent.width), static_cast<Int>(extent.height)};
outBinding.mipLevel = 0;
outBinding.mipLevelCount = 1;
outBinding.baseArrayLayer = 0;
outBinding.layerCount = 1;
outBinding.trackedLayout = nullptr;
if ((requiredAspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
outBinding.image = swapchainObject.GetImage(swapchainImageIndex);
@@ -1067,6 +1205,8 @@ void main() {
outBinding.extent = {attachmentExtent.x(), attachmentExtent.y()};
outBinding.mipLevel = static_cast<Uint32>(std::max(attachment.GetTextureLevel(), 0));
outBinding.mipLevelCount = resource->mipLevels;
outBinding.baseArrayLayer = ResolveAttachmentBaseArrayLayer(attachment);
outBinding.layerCount = 1;
return true;
}
@@ -1099,6 +1239,8 @@ void main() {
static_cast<Int>(std::max(1u, resource->extent.height >> mipLevel))};
outBinding.mipLevel = mipLevel;
outBinding.mipLevelCount = 1;
outBinding.baseArrayLayer = 0;
outBinding.layerCount = 1;
outBinding.label = "destination texture";
return true;
}
@@ -1123,6 +1265,8 @@ void main() {
outBinding.extent = {static_cast<Int>(extent.width), static_cast<Int>(extent.height)};
outBinding.mipLevel = 0;
outBinding.mipLevelCount = 1;
outBinding.baseArrayLayer = 0;
outBinding.layerCount = 1;
outBinding.trackedLayout = nullptr;
if ((requiredAspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
outBinding.image = swapchainObject.GetImage(swapchainImageIndex);
@@ -1179,6 +1323,8 @@ void main() {
outBinding.extent = {attachmentExtent.x(), attachmentExtent.y()};
outBinding.mipLevel = static_cast<Uint32>(std::max(attachment.GetTextureLevel(), 0));
outBinding.mipLevelCount = 1;
outBinding.baseArrayLayer = ResolveAttachmentBaseArrayLayer(attachment);
outBinding.layerCount = 1;
return true;
}
@@ -2166,14 +2312,7 @@ void main() {
vkCmdBeginRenderPass(frame.commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = static_cast<float>(dstTexelSize.x());
viewport.height = static_cast<float>(dstTexelSize.y());
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(frame.commandBuffer, 0, 1, &viewport);
ApplyGLViewportState(frame.commandBuffer, dstTexelSize.xy());
VkRect2D scissor{};
scissor.offset = {0, 0};
@@ -2345,6 +2484,16 @@ void main() {
}
auto cullFaceEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::CullFace);
auto depthTestEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::DepthTest);
auto polygonOffsetFillEnabled =
MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::PolygonOffsetFill) &&
DrawModeUsesPolygonFill(mode);
auto rasterizerDiscardEnabled =
MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::RasterizerDiscard);
auto colorLogicOpEnabled =
MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::ColorLogicOp) && m_logicOpFeatureEnabled;
auto stencilTestEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::StencilTest);
const StencilFaceState& frontStencil = MG_State::pGLContext->GetStencilState(StencilFace::Front);
const StencilFaceState& backStencil = MG_State::pGLContext->GetStencilState(StencilFace::Back);
auto mask = MG_State::pGLContext->GetColorMask();
const auto colorWriteMask = static_cast<VkColorComponentFlags>(
(mask.r() ? VK_COLOR_COMPONENT_R_BIT : 0u) |
@@ -2366,19 +2515,52 @@ void main() {
.frontFace = VK_FRONT_FACE_CLOCKWISE,
.depthTestEnable = depthTestEnabled,
.depthWriteEnable = depthTestEnabled && MG_State::pGLContext->GetDepthMask(),
.depthBiasEnable = polygonOffsetFillEnabled,
.rasterizerDiscardEnable = rasterizerDiscardEnabled,
.logicOpEnable = colorLogicOpEnabled,
.stencilTestEnable = stencilTestEnabled,
.depthCompareOp = MG_Util::ConvertDepthTestFuncToVkEnum(MG_State::pGLContext->GetDepthFunc()),
.logicOp = MG_Util::ConvertLogicOperationToVkEnum(MG_State::pGLContext->GetLogicOp()),
.frontStencilFailOp = MG_Util::ConvertStencilOperationToVkEnum(frontStencil.FailOp),
.frontStencilPassOp = MG_Util::ConvertStencilOperationToVkEnum(frontStencil.PassDepthPassOp),
.frontStencilDepthFailOp = MG_Util::ConvertStencilOperationToVkEnum(frontStencil.PassDepthFailOp),
.frontStencilCompareOp = MG_Util::ConvertDepthTestFuncToVkEnum(frontStencil.Func),
.backStencilFailOp = MG_Util::ConvertStencilOperationToVkEnum(backStencil.FailOp),
.backStencilPassOp = MG_Util::ConvertStencilOperationToVkEnum(backStencil.PassDepthPassOp),
.backStencilDepthFailOp = MG_Util::ConvertStencilOperationToVkEnum(backStencil.PassDepthFailOp),
.backStencilCompareOp = MG_Util::ConvertDepthTestFuncToVkEnum(backStencil.Func),
.stages = &programObj.stages,
.vertexInputState = pipelineVertexInputState
};
if (!payload.stencilTestEnable) {
payload.frontStencilFailOp = VK_STENCIL_OP_KEEP;
payload.frontStencilPassOp = VK_STENCIL_OP_KEEP;
payload.frontStencilDepthFailOp = VK_STENCIL_OP_KEEP;
payload.frontStencilCompareOp = VK_COMPARE_OP_ALWAYS;
payload.backStencilFailOp = VK_STENCIL_OP_KEEP;
payload.backStencilPassOp = VK_STENCIL_OP_KEEP;
payload.backStencilDepthFailOp = VK_STENCIL_OP_KEEP;
payload.backStencilCompareOp = VK_COMPARE_OP_ALWAYS;
}
const Bool hasDepthStencilAttachment = renderPassEntry.hasDepthStencilAttachment;
if (!hasDepthStencilAttachment && (payload.depthTestEnable || payload.depthWriteEnable)) {
MGLOG_D("GetOrCreatePipeline: disabling depth test/write for program=%u because render pass has no depth attachment (attachmentCount=%u colorAttachmentCount=%u)",
if (!hasDepthStencilAttachment &&
(payload.depthTestEnable || payload.depthWriteEnable || payload.stencilTestEnable)) {
MGLOG_D("GetOrCreatePipeline: disabling depth/stencil tests for program=%u because render pass has no depth attachment (attachmentCount=%u colorAttachmentCount=%u)",
program.GetExternalIndex(),
renderPassEntry.attachmentCount,
renderPassEntry.colorAttachmentCount);
payload.depthTestEnable = false;
payload.depthWriteEnable = false;
payload.stencilTestEnable = false;
payload.depthCompareOp = VK_COMPARE_OP_ALWAYS;
payload.frontStencilFailOp = VK_STENCIL_OP_KEEP;
payload.frontStencilPassOp = VK_STENCIL_OP_KEEP;
payload.frontStencilDepthFailOp = VK_STENCIL_OP_KEEP;
payload.frontStencilCompareOp = VK_COMPARE_OP_ALWAYS;
payload.backStencilFailOp = VK_STENCIL_OP_KEEP;
payload.backStencilPassOp = VK_STENCIL_OP_KEEP;
payload.backStencilDepthFailOp = VK_STENCIL_OP_KEEP;
payload.backStencilCompareOp = VK_COMPARE_OP_ALWAYS;
}
const Uint32 fragmentOutputMask = programObj.activeFragmentOutputLocationMask;
MOBILEGL_ASSERT(
@@ -2555,6 +2737,10 @@ void main() {
m_textureManager->CollectGarbage();
const auto& drawFbo =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
if (drawFbo != nullptr && IsUnsupportedFramebufferForDirectVulkan(*drawFbo)) {
RecordUnsupportedFramebufferError(__func__);
return false;
}
const auto& vao = *MG_State::pGLContext->GetBoundVertexArray();
const auto& program = *MG_State::pGLContext->GetCurrentProgram();
ProgramFactory::CompileOptionFlags transformFlags = GetShaderTransformFlags(m_swapchainObject.GetPreTransform());
@@ -2686,14 +2872,11 @@ void main() {
MOBILEGL_ASSERT(idxUploadOk, "SetupDraw skipped: failed to upload index buffer");
}
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = static_cast<float>(renderPassEntry->extent.x());
viewport.height = static_cast<float>(renderPassEntry->extent.y());
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(frame.commandBuffer, 0, 1, &viewport);
ApplyGLViewportState(frame.commandBuffer, renderPassEntry->extent);
ApplyBlendConstants(frame.commandBuffer);
ApplyPolygonOffsetState(frame.commandBuffer);
ApplyLineWidthState(frame.commandBuffer);
ApplyStencilState(frame.commandBuffer);
Bool scissorEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::ScissorTest);
VkRect2D scissor{};
@@ -2780,6 +2963,10 @@ void main() {
m_clearManager->CollectGarbage();
auto* fbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject().get();
MOBILEGL_ASSERT(fbo, "VulkanRenderer::Clear: draw framebuffer not found (fbo == nullptr)");
if (IsUnsupportedFramebufferForDirectVulkan(*fbo)) {
RecordUnsupportedFramebufferError(__func__);
return;
}
ClearFramebufferPayload payload {
.color = MG_State::pGLContext->GetClearColor(),
@@ -2794,6 +2981,10 @@ void main() {
m_clearManager->CollectGarbage();
auto* fbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject().get();
MOBILEGL_ASSERT(fbo, "VulkanRenderer::QueueClearBufferPayload: draw framebuffer not found");
if (IsUnsupportedFramebufferForDirectVulkan(*fbo)) {
RecordUnsupportedFramebufferError(__func__);
return;
}
auto queueAttachmentClear = [&](FramebufferAttachmentType attachmentType) {
if (attachmentType == FramebufferAttachmentType::None) {
@@ -2803,11 +2994,7 @@ void main() {
if (!attachment.IsTexture() || attachment.IsRenderbuffer()) {
return;
}
auto texture = attachment.GetTexture();
if (!texture) {
return;
}
m_clearManager->QueueClear(clearPayload, texture);
m_clearManager->QueueClear(clearPayload, attachment);
};
switch (buffer) {
@@ -2920,8 +3107,8 @@ void main() {
Bool VulkanRenderer::MaterializePendingClearForTexture(VkCommandBuffer commandBuffer,
MG_State::GLState::ITextureObject& texture) {
ClearAttachmentPayload clearPayload{};
if (!m_clearManager->GetPendingClear(&texture, clearPayload)) {
Vector<PendingClearEntry> pendingClears;
if (!m_clearManager->GetPendingClears(&texture, pendingClears)) {
return true;
}
MOBILEGL_ASSERT(VkRenderPassManager::GetActiveRenderPass() == nullptr,
@@ -2940,53 +3127,65 @@ void main() {
Bool ok = VkTextureManager::TransitionImageLayout(
commandBuffer, resource->image, resource->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT, srcAccessMask, VK_ACCESS_TRANSFER_WRITE_BIT,
resource->aspect, 0, resource->mipLevels);
resource->aspect, 0, resource->mipLevels, resource->arrayLayers);
MOBILEGL_ASSERT(ok,
"MaterializePendingClearForTexture: failed to transition textureId=%d to TRANSFER_DST",
texture.GetExternalIndex());
VkImageSubresourceRange subresourceRange{};
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1;
subresourceRange.baseArrayLayer = 0;
subresourceRange.layerCount = 1;
VkImageLayout sampledLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
if ((resource->aspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
VkClearColorValue clearValue{};
clearValue.float32[0] = clearPayload.color.x();
clearValue.float32[1] = clearPayload.color.y();
clearValue.float32[2] = clearPayload.color.z();
clearValue.float32[3] = ResolveColorClearAlpha(&texture, clearPayload.color.w());
vkCmdClearColorImage(commandBuffer, resource->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
&clearValue, 1, &subresourceRange);
} else {
VkImageAspectFlags clearAspectMask = 0;
if ((resource->aspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0 &&
(clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
clearAspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
for (const auto& pendingClear : pendingClears) {
MOBILEGL_ASSERT(pendingClear.key.mipLevel < resource->mipLevels,
"MaterializePendingClearForTexture: textureId=%d pending clear mip=%u out of range %u",
texture.GetExternalIndex(), pendingClear.key.mipLevel, resource->mipLevels);
MOBILEGL_ASSERT(pendingClear.key.baseArrayLayer + pendingClear.key.layerCount <= resource->arrayLayers,
"MaterializePendingClearForTexture: textureId=%d pending clear layer span [%u, %u) exceeds arrayLayers=%u",
texture.GetExternalIndex(), pendingClear.key.baseArrayLayer,
pendingClear.key.baseArrayLayer + pendingClear.key.layerCount, resource->arrayLayers);
VkImageSubresourceRange subresourceRange{};
subresourceRange.baseMipLevel = pendingClear.key.mipLevel;
subresourceRange.levelCount = 1;
subresourceRange.baseArrayLayer = pendingClear.key.baseArrayLayer;
subresourceRange.layerCount = pendingClear.key.layerCount;
const auto& clearPayload = pendingClear.payload;
if ((resource->aspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
VkClearColorValue clearValue{};
clearValue.float32[0] = clearPayload.color.x();
clearValue.float32[1] = clearPayload.color.y();
clearValue.float32[2] = clearPayload.color.z();
clearValue.float32[3] = ResolveColorClearAlpha(&texture, clearPayload.color.w());
vkCmdClearColorImage(commandBuffer, resource->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
&clearValue, 1, &subresourceRange);
} else {
VkImageAspectFlags clearAspectMask = 0;
if ((resource->aspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0 &&
(clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
clearAspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
}
if ((resource->aspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0 &&
(clearPayload.mask & GL_STENCIL_BUFFER_BIT) != 0) {
clearAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
MOBILEGL_ASSERT(clearAspectMask != 0,
"MaterializePendingClearForTexture: textureId=%d has no matching depth/stencil clear mask",
texture.GetExternalIndex());
subresourceRange.aspectMask = clearAspectMask;
VkClearDepthStencilValue clearValue{};
clearValue.depth = clearPayload.depth;
clearValue.stencil = clearPayload.stencil;
vkCmdClearDepthStencilImage(commandBuffer, resource->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
&clearValue, 1, &subresourceRange);
sampledLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
}
if ((resource->aspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0 &&
(clearPayload.mask & GL_STENCIL_BUFFER_BIT) != 0) {
clearAspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
MOBILEGL_ASSERT(clearAspectMask != 0,
"MaterializePendingClearForTexture: textureId=%d has no matching depth/stencil clear mask",
texture.GetExternalIndex());
subresourceRange.aspectMask = clearAspectMask;
VkClearDepthStencilValue clearValue{};
clearValue.depth = clearPayload.depth;
clearValue.stencil = clearPayload.stencil;
vkCmdClearDepthStencilImage(commandBuffer, resource->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
&clearValue, 1, &subresourceRange);
sampledLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
}
ok = VkTextureManager::TransitionImageLayout(
commandBuffer, resource->image, clearLayout, sampledLayout,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, resource->aspect, 0, resource->mipLevels);
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, resource->aspect, 0, resource->mipLevels,
resource->arrayLayers);
MOBILEGL_ASSERT(ok,
"MaterializePendingClearForTexture: failed to transition textureId=%d to sampled layout",
texture.GetExternalIndex());
@@ -3054,14 +3253,7 @@ void main() {
const Bool ok = VkRenderPassManager::BeginRenderPass(frame.commandBuffer, renderPassEntry);
MOBILEGL_ASSERT(ok, "%s: BeginRenderPass failed", __func__);
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = static_cast<float>(renderPassEntry.extent.x());
viewport.height = static_cast<float>(renderPassEntry.extent.y());
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(frame.commandBuffer, 0, 1, &viewport);
ApplyGLViewportState(frame.commandBuffer, renderPassEntry.extent);
VkRect2D scissor{};
scissor.offset = {0, 0};
@@ -3163,6 +3355,11 @@ void main() {
auto drawFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
MOBILEGL_ASSERT(readFbo != nullptr, "VulkanRenderer::BlitFramebuffer: read framebuffer is null");
MOBILEGL_ASSERT(drawFbo != nullptr, "VulkanRenderer::BlitFramebuffer: draw framebuffer is null");
if (IsUnsupportedFramebufferForDirectVulkan(*readFbo) ||
IsUnsupportedFramebufferForDirectVulkan(*drawFbo)) {
RecordUnsupportedFramebufferError(__func__);
return;
}
auto& frame = m_frameContext.GetCurrent();
if (!frame.isCommandRecording) {
@@ -3285,13 +3482,13 @@ void main() {
VkImageCopy copyRegion{};
copyRegion.srcSubresource.aspectMask = srcBinding.aspectMask;
copyRegion.srcSubresource.mipLevel = srcBinding.mipLevel;
copyRegion.srcSubresource.baseArrayLayer = 0;
copyRegion.srcSubresource.layerCount = 1;
copyRegion.srcSubresource.baseArrayLayer = srcBinding.baseArrayLayer;
copyRegion.srcSubresource.layerCount = srcBinding.layerCount;
copyRegion.srcOffset = {srcX0, srcY0, 0};
copyRegion.dstSubresource.aspectMask = dstBinding.aspectMask;
copyRegion.dstSubresource.mipLevel = dstBinding.mipLevel;
copyRegion.dstSubresource.baseArrayLayer = 0;
copyRegion.dstSubresource.layerCount = 1;
copyRegion.dstSubresource.baseArrayLayer = dstBinding.baseArrayLayer;
copyRegion.dstSubresource.layerCount = dstBinding.layerCount;
copyRegion.dstOffset = {dstX0, dstY0, 0};
copyRegion.extent = {static_cast<Uint32>(srcWidth), static_cast<Uint32>(srcHeight), 1};
@@ -3421,14 +3618,14 @@ void main() {
VkImageBlit blitRegion{};
blitRegion.srcSubresource.aspectMask = srcBinding.aspectMask;
blitRegion.srcSubresource.mipLevel = srcBinding.mipLevel;
blitRegion.srcSubresource.baseArrayLayer = 0;
blitRegion.srcSubresource.layerCount = 1;
blitRegion.srcSubresource.baseArrayLayer = srcBinding.baseArrayLayer;
blitRegion.srcSubresource.layerCount = srcBinding.layerCount;
blitRegion.srcOffsets[0] = {srcX0, srcY0, 0};
blitRegion.srcOffsets[1] = {srcX1, srcY1, 1};
blitRegion.dstSubresource.aspectMask = dstBinding.aspectMask;
blitRegion.dstSubresource.mipLevel = dstBinding.mipLevel;
blitRegion.dstSubresource.baseArrayLayer = 0;
blitRegion.dstSubresource.layerCount = 1;
blitRegion.dstSubresource.baseArrayLayer = dstBinding.baseArrayLayer;
blitRegion.dstSubresource.layerCount = dstBinding.layerCount;
blitRegion.dstOffsets[0] = {dstX0, dstY0, 0};
blitRegion.dstOffsets[1] = {dstX1, dstY1, 1};
if (drawIsDefaultFbo) {
@@ -3503,6 +3700,11 @@ void main() {
"CopyTexSubImage2D requires a framebuffer bound to GL_READ_FRAMEBUFFER.");
return;
}
if (IsUnsupportedFramebufferForDirectVulkan(*readFbo)) {
RecordTextureCopyError(__func__, ErrorCode::InvalidFramebufferOperation,
"CopyTexSubImage2D does not support the current non-default read framebuffer configuration on DirectVulkan.");
return;
}
auto& frame = m_frameContext.GetCurrent();
if (!frame.isCommandRecording) {
@@ -3601,13 +3803,13 @@ void main() {
VkImageCopy copyRegion{};
copyRegion.srcSubresource.aspectMask = srcBinding.aspectMask;
copyRegion.srcSubresource.mipLevel = srcBinding.mipLevel;
copyRegion.srcSubresource.baseArrayLayer = 0;
copyRegion.srcSubresource.layerCount = 1;
copyRegion.srcSubresource.baseArrayLayer = srcBinding.baseArrayLayer;
copyRegion.srcSubresource.layerCount = srcBinding.layerCount;
copyRegion.srcOffset = {x, y, 0};
copyRegion.dstSubresource.aspectMask = dstBinding.aspectMask;
copyRegion.dstSubresource.mipLevel = dstBinding.mipLevel;
copyRegion.dstSubresource.baseArrayLayer = 0;
copyRegion.dstSubresource.layerCount = 1;
copyRegion.dstSubresource.baseArrayLayer = dstBinding.baseArrayLayer;
copyRegion.dstSubresource.layerCount = dstBinding.layerCount;
copyRegion.dstOffset = {xoffset, yoffset, 0};
copyRegion.extent = {static_cast<Uint32>(width), static_cast<Uint32>(height), 1};
vkCmdCopyImage(frame.commandBuffer,
@@ -4064,7 +4266,8 @@ void main() {
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
MGLOG_D("Present, vkAcquireNextImageKHR got %d, recreating swapchain", result);
RecreateSwapchain();
result = VK_SUCCESS;
result =
m_frameContext.WaitAndAcquireNextImage(m_device, m_swapchainObject.GetHandle(), m_imageIndexAcquired);
}
VK_VERIFY(result, "Present, vkAcquireNextImageKHR");
CollectDeferredDepthMipmapCleanup(m_frameContext.GetCurrentFrameIndex());
@@ -4350,8 +4553,11 @@ void main() {
VkPhysicalDeviceFeatures deviceFeatures{};
deviceFeatures.geometryShader = supportedDeviceFeatures.geometryShader;
deviceFeatures.independentBlend = supportedDeviceFeatures.independentBlend;
deviceFeatures.logicOp = supportedDeviceFeatures.logicOp;
deviceFeatures.shaderClipDistance = supportedDeviceFeatures.shaderClipDistance;
deviceFeatures.shaderCullDistance = supportedDeviceFeatures.shaderCullDistance;
deviceFeatures.wideLines = supportedDeviceFeatures.wideLines;
m_logicOpFeatureEnabled = deviceFeatures.logicOp == VK_TRUE;
VkDeviceCreateInfo deviceCreateInfo{};
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
@@ -4416,16 +4622,20 @@ void main() {
deviceCreateInfo.enabledExtensionCount = static_cast<Uint32>(enabledDeviceExtensions.size());
deviceCreateInfo.ppEnabledExtensionNames = enabledDeviceExtensions.data();
MGLOG_I("Device feature support: geometryShader=%s independentBlend=%s shaderClipDistance=%s shaderCullDistance=%s",
MGLOG_I("Device feature support: geometryShader=%s independentBlend=%s logicOp=%s shaderClipDistance=%s shaderCullDistance=%s wideLines=%s",
supportedDeviceFeatures.geometryShader ? "true" : "false",
supportedDeviceFeatures.independentBlend ? "true" : "false",
supportedDeviceFeatures.logicOp ? "true" : "false",
supportedDeviceFeatures.shaderClipDistance ? "true" : "false",
supportedDeviceFeatures.shaderCullDistance ? "true" : "false");
MGLOG_I("Device feature enabled: geometryShader=%s independentBlend=%s shaderClipDistance=%s shaderCullDistance=%s",
supportedDeviceFeatures.shaderCullDistance ? "true" : "false",
supportedDeviceFeatures.wideLines ? "true" : "false");
MGLOG_I("Device feature enabled: geometryShader=%s independentBlend=%s logicOp=%s shaderClipDistance=%s shaderCullDistance=%s wideLines=%s",
deviceFeatures.geometryShader ? "true" : "false",
deviceFeatures.independentBlend ? "true" : "false",
deviceFeatures.logicOp ? "true" : "false",
deviceFeatures.shaderClipDistance ? "true" : "false",
deviceFeatures.shaderCullDistance ? "true" : "false");
deviceFeatures.shaderCullDistance ? "true" : "false",
deviceFeatures.wideLines ? "true" : "false");
VK_VERIFY(vkCreateDevice(m_physicalDevice.handle, &deviceCreateInfo, nullptr, &m_device), "vkCreateDevice");
s_vkCmdDrawIndexedIndirectCount = reinterpret_cast<PFNDrawIndexedIndirectCountFunc>(
@@ -4726,12 +4936,12 @@ void main() {
clearRect.layerCount = 1;
for (const auto& pending : compatibleRenderPassEntry.pendingClearAttachments) {
if (!pending.texture) {
if (pending.key.texture == nullptr) {
continue;
}
ClearAttachmentPayload clearPayload{};
if (!m_clearManager->GetPendingClear(pending.texture, clearPayload)) {
if (!m_clearManager->GetPendingClear(pending.key, clearPayload)) {
continue;
}
@@ -4744,7 +4954,7 @@ void main() {
clearPayload.color.x(),
clearPayload.color.y(),
clearPayload.color.z(),
ResolveColorClearAlpha(pending.texture, clearPayload.color.w())
ResolveColorClearAlpha(pending.key.texture, clearPayload.color.w())
};
} else {
if ((clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0) {
@@ -4761,7 +4971,7 @@ void main() {
}
vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect);
m_clearManager->PopPendingClear(pending.texture);
m_clearManager->PopPendingClear(pending.key);
}
}
@@ -195,6 +195,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkQueue m_presentQueue = VK_NULL_HANDLE;
Bool m_drawIndirectCountExtensionEnabled = false;
Bool m_indexTypeUint8ExtensionEnabled = false;
Bool m_logicOpFeatureEnabled = false;
using PFNDrawIndexedIndirectCountFunc = void(VKAPI_PTR*)(VkCommandBuffer commandBuffer, VkBuffer buffer,
VkDeviceSize offset, VkBuffer countBuffer,
VkDeviceSize countBufferOffset, Uint32 maxDrawCount,
+3
View File
@@ -258,6 +258,9 @@ namespace MobileGL::MG_Impl::EGLImpl {
if (!state) {
return EGL_FALSE;
}
if (auto* backendObject = MG_Backend::pActiveBackendObject.get()) {
(void)backendObject->MakeEGLCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
state->ReleaseThread();
return EGL_TRUE;
}
+120 -11
View File
@@ -80,6 +80,93 @@ namespace MobileGL::MG_Impl::GLImpl {
}
}
void GetBufferPointerv_State(GLenum target, GLenum pname, void** params) {
if (!params) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetBufferPointerv_State",
"Params pointer cannot be null."));
return;
}
BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target);
if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return;
auto& bindingSlot = GetBufferBindingSlot(bufferTarget);
auto& bufferObject = bindingSlot.GetBoundObject();
if (!bufferObject) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetBufferPointerv_State",
"Buffer target is bound to no buffer object."));
return;
}
if (pname != GL_BUFFER_MAP_POINTER) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetBufferPointerv_State",
std::format("Invalid pname enum: 0x{:X}", pname)));
return;
}
*params = bufferObject->GetMappedPointer();
}
void GetBufferParameteri64v_State(GLenum target, GLenum pname, GLint64* params) {
if (!params) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetBufferParameteri64v_State",
"Params pointer cannot be null."));
return;
}
BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target);
if (!BufferImpl::ValidateBufferTarget(bufferTarget)) return;
auto& bindingSlot = GetBufferBindingSlot(bufferTarget);
auto& bufferObject = bindingSlot.GetBoundObject();
if (!bufferObject) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetBufferParameteri64v_State",
"Buffer target is bound to no buffer object."));
return;
}
switch (pname) {
case GL_BUFFER_SIZE:
*params = static_cast<GLint64>(bufferObject->GetSize());
break;
case GL_BUFFER_USAGE:
*params = static_cast<GLint64>(MG_Util::ConvertBufferUsageToGLEnum(bufferObject->GetUsage()));
break;
case GL_BUFFER_ACCESS:
if (bufferObject->IsMapped()) {
auto access = bufferObject->GetMappingAccess();
if (access & BufferMappingAccessBit::Read && access & BufferMappingAccessBit::Write) {
*params = GL_READ_WRITE;
} else if (access & BufferMappingAccessBit::Read) {
*params = GL_READ_ONLY;
} else if (access & BufferMappingAccessBit::Write) {
*params = GL_WRITE_ONLY;
} else {
*params = 0;
}
} else {
*params = 0;
}
break;
case GL_BUFFER_MAPPED:
*params = bufferObject->IsMapped() ? GL_TRUE : GL_FALSE;
break;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetBufferParameteri64v_State",
std::format("Invalid pname enum: 0x{:X}", pname)));
break;
}
}
void DeleteBuffers_State(GLsizei n, const GLuint* buffers) {
if (n < 0) {
MG_State::pGLContext->RecordError(
@@ -524,16 +611,23 @@ namespace MobileGL::MG_Impl::GLImpl {
BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target);
if (!BufferImpl::ValidateBufferBindingPointTarget(bufferTarget)) return;
Bool doesBufferObjectCreated = MG_State::pGLContext->ValidateBufferObject(buffer);
if (!doesBufferObjectCreated) {
MG_State::pGLContext->CreateBufferObject(buffer);
SharedPtr<MG_State::GLState::BufferObject> bufferObject;
if (buffer != 0) {
Bool doesBufferObjectCreated = MG_State::pGLContext->ValidateBufferObject(buffer);
if (!doesBufferObjectCreated) {
MG_State::pGLContext->CreateBufferObject(buffer);
}
bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
}
auto& bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
auto& point = MG_State::pGLContext->GetBufferBindingPoint(bufferTarget, pointIndex);
point.Bind(bufferObject);
point.SetRange(Range1D(0, bufferObject->GetSize()));
MGLOG_D("%s: set range (0, %d)", __func__, bufferObject->GetSize());
if (bufferObject) {
point.SetRange(Range1D(0, bufferObject->GetSize()));
MGLOG_D("%s: set range (0, %d)", __func__, bufferObject->GetSize());
} else {
point.ClearRange();
}
}
void BindBufferRange_State(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) {
@@ -542,15 +636,22 @@ namespace MobileGL::MG_Impl::GLImpl {
BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target);
if (!BufferImpl::ValidateBufferBindingPointTarget(bufferTarget)) return;
Bool doesBufferObjectCreated = MG_State::pGLContext->ValidateBufferObject(buffer);
if (!doesBufferObjectCreated) {
MG_State::pGLContext->CreateBufferObject(buffer);
SharedPtr<MG_State::GLState::BufferObject> bufferObject;
if (buffer != 0) {
Bool doesBufferObjectCreated = MG_State::pGLContext->ValidateBufferObject(buffer);
if (!doesBufferObjectCreated) {
MG_State::pGLContext->CreateBufferObject(buffer);
}
bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
}
auto& bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
auto& point = MG_State::pGLContext->GetBufferBindingPoint(bufferTarget, index);
point.Bind(bufferObject);
point.SetRange(Range1D(offset, offset + size));
if (bufferObject) {
point.SetRange(Range1D(offset, offset + size));
} else {
point.ClearRange();
}
}
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
@@ -558,6 +659,14 @@ namespace MobileGL::MG_Impl::GLImpl {
GetBufferParameteriv_State(target, pname, params);
}
void GetBufferPointerv(GLenum target, GLenum pname, void** params) {
GetBufferPointerv_State(target, pname, params);
}
void GetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params) {
GetBufferParameteri64v_State(target, pname, params);
}
GLboolean IsBuffer(GLuint buffer) {
return IsBuffer_State(buffer);
}
@@ -12,6 +12,8 @@
namespace MobileGL::MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
void GetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params);
void GetBufferPointerv(GLenum target, GLenum pname, void** params);
GLboolean IsBuffer(GLuint buffer);
void DeleteBuffers(GLsizei n, const GLuint* buffers);
void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length);
@@ -12,6 +12,62 @@
#include <MG_Backend/BackendObjects.h>
namespace MobileGL::MG_Impl::GLImpl {
static Bool ValidateCurrentProgramForExecution(const char* functionName) {
const auto& currentProgram = MG_State::pGLContext->GetCurrentProgram();
if (!currentProgram) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName, "There is no current program object."));
return false;
}
if (!currentProgram->GetLinkStatus()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName,
"The current program object is not linked."));
return false;
}
return true;
}
static Bool ValidateCurrentProgramForCompute(const char* functionName) {
if (!ValidateCurrentProgramForExecution(functionName)) return false;
const auto& currentProgram = MG_State::pGLContext->GetCurrentProgram();
if (currentProgram->GetShaderIndexByStage(ShaderStage::Compute) < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName,
"The current program object has no compute shader stage."));
return false;
}
return true;
}
static Bool ValidatePrimitiveModeForBackend(const char* functionName, GLenum mode) {
const auto& activeBackendObject = MG_Backend::pActiveBackendObject;
if (!activeBackendObject) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName, "No active backend object."));
return false;
}
if (activeBackendObject->GetBackendType() == BackendType::DirectVulkan && mode == GL_LINE_LOOP) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", functionName,
"Primitive mode GL_LINE_LOOP is not supported by the DirectVulkan backend."));
return false;
}
return true;
}
void Clear_Backend(GLbitfield mask) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
@@ -164,6 +220,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Backend does not support compute dispatch."));
return;
}
if (!ValidateCurrentProgramForCompute(__func__)) return;
dispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
}
@@ -176,6 +233,7 @@ namespace MobileGL::MG_Impl::GLImpl {
"Backend does not support indirect compute dispatch."));
return;
}
if (!ValidateCurrentProgramForCompute(__func__)) return;
dispatchComputeIndirect(indirect);
}
@@ -203,74 +261,106 @@ namespace MobileGL::MG_Impl::GLImpl {
}
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
MultiDrawElementsIndirect_Backend(mode, type, indirect, drawcount, stride);
}
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
MultiDrawArraysIndirect_Backend(mode, indirect, drawcount, stride);
}
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
DrawRangeElementsBaseVertex_Backend(mode, start, end, count, type, indices, basevertex);
}
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
DrawRangeElements_Backend(mode, start, end, count, type, indices);
}
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
GLsizei instancecount, GLint basevertex, GLuint baseinstance) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
DrawElementsInstancedBaseVertexBaseInstance_Backend(mode, count, type, indices, instancecount, basevertex,
baseinstance);
}
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
GLsizei instancecount, GLint basevertex) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
DrawElementsInstancedBaseVertex_Backend(mode, count, type, indices, instancecount, basevertex);
}
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
GLsizei instancecount, GLuint baseinstance) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
DrawElementsInstancedBaseInstance_Backend(mode, count, type, indices, instancecount, baseinstance);
}
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
DrawElementsInstanced_Backend(mode, count, type, indices, instancecount);
}
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
DrawElementsIndirect_Backend(mode, type, indirect);
}
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
GLuint baseinstance) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
DrawArraysInstancedBaseInstance_Backend(mode, first, count, instancecount, baseinstance);
}
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
DrawArraysInstanced_Backend(mode, first, count, instancecount);
}
void DrawArraysIndirect(GLenum mode, const void* indirect) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
DrawArraysIndirect_Backend(mode, indirect);
}
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
DrawElementsBaseVertex_Backend(mode, count, type, indices, basevertex);
}
void DrawArrays(GLenum mode, GLint first, GLsizei count) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
DrawArrays_Backend(mode, first, count);
}
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
GLsizei drawcount) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
MultiDrawElements_Backend(mode, count, type, indices, drawcount);
}
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
GLsizei drawcount, const GLint* basevertex) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
MultiDrawElementsBaseVertex_Backend(mode, count, type, indices, drawcount, basevertex);
}
@@ -279,6 +369,8 @@ namespace MobileGL::MG_Impl::GLImpl {
}
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
if (!ValidateCurrentProgramForExecution(__func__)) return;
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
DrawElements_Backend(mode, count, type, indices);
}
@@ -16,6 +16,7 @@
#include "../RenderState/GL_RenderState.h"
#include "../Framebuffer/GL_Framebuffer.h"
#include "../VertexArray/GL_VertexArray.h"
#include "../Sync/GL_Sync.h"
#define DECLARE_GL_FUNCTION_STUB_HEAD(type, name, ...) MOBILEGL_GL_API type gl##name(__VA_ARGS__) {
@@ -75,7 +76,7 @@ DECLARE_GL_FUNCTION_HEAD(void, BufferSubData, GLenum target, GLintptr offset, GL
DECLARE_GL_FUNCTION_HEAD(GLenum, CheckFramebufferStatus, GLenum target) DECLARE_GL_FUNCTION_END(GLenum, CheckFramebufferStatus, target)
DECLARE_GL_FUNCTION_HEAD(void, Clear, GLbitfield mask) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Clear, mask)
DECLARE_GL_FUNCTION_HEAD(void, ClearColor, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearColor, red, green, blue, alpha)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearDepthf, GLfloat d) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearDepthf, d)
DECLARE_GL_FUNCTION_HEAD(void, ClearDepthf, GLfloat d) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearDepth, static_cast<GLclampd>(d))
DECLARE_GL_FUNCTION_HEAD(void, ClearStencil, GLint s) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearStencil, s)
DECLARE_GL_FUNCTION_HEAD(void, ColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ColorMask, red, green, blue, alpha)
DECLARE_GL_FUNCTION_HEAD(void, CompileShader, GLuint shader) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CompileShader, shader)
@@ -94,7 +95,7 @@ DECLARE_GL_FUNCTION_HEAD(void, DeleteShader, GLuint shader) DECLARE_GL_FUNCTION_
DECLARE_GL_FUNCTION_HEAD(void, DeleteTextures, GLsizei n, const GLuint* textures) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteTextures, n, textures)
DECLARE_GL_FUNCTION_HEAD(void, DepthFunc, GLenum func) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DepthFunc, func)
DECLARE_GL_FUNCTION_HEAD(void, DepthMask, GLboolean flag) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DepthMask, flag)
DECLARE_GL_FUNCTION_STUB_HEAD(void, DepthRangef, GLfloat n, GLfloat f) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DepthRangef, n, f)
DECLARE_GL_FUNCTION_HEAD(void, DepthRangef, GLfloat n, GLfloat f) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DepthRange, static_cast<GLclampd>(n), static_cast<GLclampd>(f))
DECLARE_GL_FUNCTION_HEAD(void, DetachShader, GLuint program, GLuint shader) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DetachShader, program, shader)
DECLARE_GL_FUNCTION_HEAD(void, Disable, GLenum cap) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Disable, cap)
DECLARE_GL_FUNCTION_HEAD(void, DisableVertexAttribArray, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DisableVertexAttribArray, index)
@@ -116,10 +117,10 @@ DECLARE_GL_FUNCTION_HEAD(void, GetActiveAttrib, GLuint program, GLuint index, GL
DECLARE_GL_FUNCTION_HEAD(void, GetActiveUniform, GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetActiveUniform, program, index, bufSize, length, size, type, name)
DECLARE_GL_FUNCTION_HEAD(void, GetAttachedShaders, GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetAttachedShaders, program, maxCount, count, shaders)
DECLARE_GL_FUNCTION_HEAD(GLint, GetAttribLocation, GLuint program, const GLchar* name) DECLARE_GL_FUNCTION_END(GLint, GetAttribLocation, program, name)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBooleanv, GLenum pname, GLboolean* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBooleanv, pname, data)
DECLARE_GL_FUNCTION_HEAD(void, GetBooleanv, GLenum pname, GLboolean* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetBooleanv, pname, data)
DECLARE_GL_FUNCTION_HEAD(void, GetBufferParameteriv, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetBufferParameteriv, target, pname, params)
DECLARE_GL_FUNCTION_HEAD(GLenum, GetError) DECLARE_GL_FUNCTION_END(GLenum, GetError)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetFloatv, GLenum pname, GLfloat* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetFloatv, pname, data)
DECLARE_GL_FUNCTION_HEAD(void, GetFloatv, GLenum pname, GLfloat* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetFloatv, pname, data)
DECLARE_GL_FUNCTION_HEAD(void, GetFramebufferAttachmentParameteriv, GLenum target, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetFramebufferAttachmentParameteriv, target, attachment, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, GetIntegerv, GLenum pname, GLint* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetIntegerv, pname, data)
DECLARE_GL_FUNCTION_HEAD(void, GetProgramiv, GLuint program, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetProgramiv, program, pname, params)
@@ -134,9 +135,9 @@ DECLARE_GL_FUNCTION_HEAD(void, GetTexParameteriv, GLenum target, GLenum pname, G
DECLARE_GL_FUNCTION_HEAD(void, GetUniformfv, GLuint program, GLint location, GLfloat* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetUniformfv, program, location, params)
DECLARE_GL_FUNCTION_HEAD(void, GetUniformiv, GLuint program, GLint location, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetUniformiv, program, location, params)
DECLARE_GL_FUNCTION_HEAD(GLint, GetUniformLocation, GLuint program, const GLchar* name) DECLARE_GL_FUNCTION_END(GLint, GetUniformLocation, program, name)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexAttribfv, GLuint index, GLenum pname, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexAttribfv, index, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexAttribiv, GLuint index, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexAttribiv, index, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexAttribPointerv, GLuint index, GLenum pname, void** pointer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexAttribPointerv, index, pname, pointer)
DECLARE_GL_FUNCTION_HEAD(void, GetVertexAttribfv, GLuint index, GLenum pname, GLfloat* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetVertexAttribfv, index, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, GetVertexAttribiv, GLuint index, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetVertexAttribiv, index, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, GetVertexAttribPointerv, GLuint index, GLenum pname, void** pointer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetVertexAttribPointerv, index, pname, pointer)
DECLARE_GL_FUNCTION_HEAD(void, Hint, GLenum target, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Hint, target, mode)
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsBuffer, GLuint buffer) DECLARE_GL_FUNCTION_END(GLboolean, IsBuffer, buffer)
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsEnabled, GLenum cap) DECLARE_GL_FUNCTION_END(GLboolean, IsEnabled, cap)
@@ -189,14 +190,14 @@ DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix3fv, GLint location, GLsizei count,
DECLARE_GL_FUNCTION_HEAD(void, UniformMatrix4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformMatrix4fv, location, count, transpose, value)
DECLARE_GL_FUNCTION_HEAD(void, UseProgram, GLuint program) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UseProgram, program)
DECLARE_GL_FUNCTION_HEAD(void, ValidateProgram, GLuint program) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ValidateProgram, program)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib1f, GLuint index, GLfloat x) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib1f, index, x)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib1fv, GLuint index, const GLfloat* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib1fv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib2f, GLuint index, GLfloat x, GLfloat y) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib2f, index, x, y)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib2fv, GLuint index, const GLfloat* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib2fv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib3f, GLuint index, GLfloat x, GLfloat y, GLfloat z) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib3f, index, x, y, z)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib3fv, GLuint index, const GLfloat* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib3fv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4f, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4f, index, x, y, z, w)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4fv, GLuint index, const GLfloat* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4fv, index, v)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttrib1f, GLuint index, GLfloat x) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttrib1f, index, x)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttrib1fv, GLuint index, const GLfloat* v) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttrib1fv, index, v)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttrib2f, GLuint index, GLfloat x, GLfloat y) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttrib2f, index, x, y)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttrib2fv, GLuint index, const GLfloat* v) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttrib2fv, index, v)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttrib3f, GLuint index, GLfloat x, GLfloat y, GLfloat z) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttrib3f, index, x, y, z)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttrib3fv, GLuint index, const GLfloat* v) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttrib3fv, index, v)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttrib4f, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttrib4f, index, x, y, z, w)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttrib4fv, GLuint index, const GLfloat* v) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttrib4fv, index, v)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttribPointer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttribPointer, index, size, type, normalized, stride, pointer)
DECLARE_GL_FUNCTION_HEAD(void, Viewport, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Viewport, x, y, width, height)
DECLARE_GL_FUNCTION_HEAD(void, ReadBuffer, GLenum src) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ReadBuffer, src)
@@ -214,7 +215,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, EndQuery, GLenum target) DECLARE_GL_FUNCTION
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryiv, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryiv, target, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryObjectuiv, GLuint id, GLenum pname, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryObjectuiv, id, pname, params)
DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapBuffer, GLenum target) DECLARE_GL_FUNCTION_END(GLboolean, UnmapBuffer, target)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBufferPointerv, GLenum target, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBufferPointerv, target, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, GetBufferPointerv, GLenum target, GLenum pname, void** params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetBufferPointerv, target, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, DrawBuffers, GLsizei n, const GLenum* bufs) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawBuffers, n, bufs)
DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix2x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix2x3fv, location, count, transpose, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, UniformMatrix3x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, UniformMatrix3x2fv, location, count, transpose, value)
@@ -239,28 +240,28 @@ DECLARE_GL_FUNCTION_HEAD(void, BindBufferBase, GLenum target, GLuint index, GLui
DECLARE_GL_FUNCTION_STUB_HEAD(void, TransformFeedbackVaryings, GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TransformFeedbackVaryings, program, count, varyings, bufferMode)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbackVarying, GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbackVarying, program, index, bufSize, length, size, type, name)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttribIPointer, GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttribIPointer, index, size, type, stride, pointer)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexAttribIiv, GLuint index, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexAttribIiv, index, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexAttribIuiv, GLuint index, GLenum pname, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexAttribIuiv, index, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribI4i, GLuint index, GLint x, GLint y, GLint z, GLint w) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribI4i, index, x, y, z, w)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribI4ui, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribI4ui, index, x, y, z, w)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribI4iv, GLuint index, const GLint* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribI4iv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribI4uiv, GLuint index, const GLuint* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribI4uiv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetUniformuiv, GLuint program, GLint location, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetUniformuiv, program, location, params)
DECLARE_GL_FUNCTION_HEAD(void, GetVertexAttribIiv, GLuint index, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetVertexAttribIiv, index, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, GetVertexAttribIuiv, GLuint index, GLenum pname, GLuint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetVertexAttribIuiv, index, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttribI4i, GLuint index, GLint x, GLint y, GLint z, GLint w) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttribI4i, index, x, y, z, w)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttribI4ui, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttribI4ui, index, x, y, z, w)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttribI4iv, GLuint index, const GLint* v) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttribI4iv, index, v)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttribI4uiv, GLuint index, const GLuint* v) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttribI4uiv, index, v)
DECLARE_GL_FUNCTION_HEAD(void, GetUniformuiv, GLuint program, GLint location, GLuint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetUniformuiv, program, location, params)
DECLARE_GL_FUNCTION_HEAD(GLint, GetFragDataLocation, GLuint program, const GLchar* name) DECLARE_GL_FUNCTION_END(GLint, GetFragDataLocation, program, name)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform1ui, GLint location, GLuint v0) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform1ui, location, v0)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform2ui, GLint location, GLuint v0, GLuint v1) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform2ui, location, v0, v1)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform3ui, GLint location, GLuint v0, GLuint v1, GLuint v2) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform3ui, location, v0, v1, v2)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform4ui, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform4ui, location, v0, v1, v2, v3)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform1uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform1uiv, location, count, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform2uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform2uiv, location, count, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform3uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform3uiv, location, count, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Uniform4uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Uniform4uiv, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, Uniform1ui, GLint location, GLuint v0) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform1ui, location, v0)
DECLARE_GL_FUNCTION_HEAD(void, Uniform2ui, GLint location, GLuint v0, GLuint v1) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform2ui, location, v0, v1)
DECLARE_GL_FUNCTION_HEAD(void, Uniform3ui, GLint location, GLuint v0, GLuint v1, GLuint v2) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform3ui, location, v0, v1, v2)
DECLARE_GL_FUNCTION_HEAD(void, Uniform4ui, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform4ui, location, v0, v1, v2, v3)
DECLARE_GL_FUNCTION_HEAD(void, Uniform1uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform1uiv, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, Uniform2uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform2uiv, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, Uniform3uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform3uiv, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, Uniform4uiv, GLint location, GLsizei count, const GLuint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Uniform4uiv, location, count, value)
DECLARE_GL_FUNCTION_HEAD(void, ClearBufferiv, GLenum buffer, GLint drawbuffer, const GLint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearBufferiv, buffer, drawbuffer, value)
DECLARE_GL_FUNCTION_HEAD(void, ClearBufferuiv, GLenum buffer, GLint drawbuffer, const GLuint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearBufferuiv, buffer, drawbuffer, value)
DECLARE_GL_FUNCTION_HEAD(void, ClearBufferfv, GLenum buffer, GLint drawbuffer, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearBufferfv, buffer, drawbuffer, value)
DECLARE_GL_FUNCTION_HEAD(void, ClearBufferfi, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearBufferfi, buffer, drawbuffer, depth, stencil)
DECLARE_GL_FUNCTION_HEAD(void, CopyBufferSubData, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CopyBufferSubData, readTarget, writeTarget, readOffset, writeOffset, size)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetUniformIndices, GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetUniformIndices, program, uniformCount, uniformNames, uniformIndices)
DECLARE_GL_FUNCTION_HEAD(void, GetUniformIndices, GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetUniformIndices, program, uniformCount, uniformNames, uniformIndices)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetActiveUniformsiv, GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetActiveUniformsiv, program, uniformCount, uniformIndices, pname, params)
DECLARE_GL_FUNCTION_HEAD(GLuint, GetUniformBlockIndex, GLuint program, const GLchar* uniformBlockName) DECLARE_GL_FUNCTION_END(GLuint, GetUniformBlockIndex, program, uniformBlockName)
DECLARE_GL_FUNCTION_HEAD(void, GetActiveUniformBlockiv, GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetActiveUniformBlockiv, program, uniformBlockIndex, pname, params)
@@ -268,15 +269,15 @@ DECLARE_GL_FUNCTION_HEAD(void, GetActiveUniformBlockName, GLuint program, GLuint
DECLARE_GL_FUNCTION_HEAD(void, UniformBlockBinding, GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) DECLARE_GL_FUNCTION_END_NO_RETURN(void, UniformBlockBinding, program, uniformBlockIndex, uniformBlockBinding)
DECLARE_GL_FUNCTION_HEAD(void, DrawArraysInstanced, GLenum mode, GLint first, GLsizei count, GLsizei instancecount) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawArraysInstanced, mode, first, count, instancecount)
DECLARE_GL_FUNCTION_HEAD(void, DrawElementsInstanced, GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsInstanced, mode, count, type, indices, instancecount)
DECLARE_GL_FUNCTION_STUB_HEAD(GLsync, FenceSync, GLenum condition, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_END(GLsync, FenceSync, condition, flags)
DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, IsSync, GLsync sync) DECLARE_GL_FUNCTION_STUB_END(GLboolean, IsSync, sync)
DECLARE_GL_FUNCTION_STUB_HEAD(void, DeleteSync, GLsync sync) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DeleteSync, sync)
DECLARE_GL_FUNCTION_STUB_HEAD(GLenum, ClientWaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_STUB_END(GLenum, ClientWaitSync, sync, flags, timeout)
DECLARE_GL_FUNCTION_STUB_HEAD(void, WaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, WaitSync, sync, flags, timeout)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetInteger64v, GLenum pname, GLint64* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetInteger64v, pname, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetSynciv, GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetSynciv, sync, pname, bufSize, length, values)
DECLARE_GL_FUNCTION_HEAD(GLsync, FenceSync, GLenum condition, GLbitfield flags) DECLARE_GL_FUNCTION_END(GLsync, FenceSync, condition, flags)
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsSync, GLsync sync) DECLARE_GL_FUNCTION_END(GLboolean, IsSync, sync)
DECLARE_GL_FUNCTION_HEAD(void, DeleteSync, GLsync sync) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteSync, sync)
DECLARE_GL_FUNCTION_HEAD(GLenum, ClientWaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_END(GLenum, ClientWaitSync, sync, flags, timeout)
DECLARE_GL_FUNCTION_HEAD(void, WaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) DECLARE_GL_FUNCTION_END_NO_RETURN(void, WaitSync, sync, flags, timeout)
DECLARE_GL_FUNCTION_HEAD(void, GetInteger64v, GLenum pname, GLint64* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetInteger64v, pname, data)
DECLARE_GL_FUNCTION_HEAD(void, GetSynciv, GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetSynciv, sync, pname, bufSize, length, values)
DECLARE_GL_FUNCTION_HEAD(void, GetInteger64i_v, GLenum target, GLuint index, GLint64* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetInteger64i_v, target, index, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBufferParameteri64v, GLenum target, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBufferParameteri64v, target, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, GetBufferParameteri64v, GLenum target, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetBufferParameteri64v, target, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, GenSamplers, GLsizei count, GLuint* samplers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GenSamplers, count, samplers)
DECLARE_GL_FUNCTION_HEAD(void, DeleteSamplers, GLsizei count, const GLuint* samplers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DeleteSamplers, count, samplers)
DECLARE_GL_FUNCTION_HEAD(GLboolean, IsSampler, GLuint sampler) DECLARE_GL_FUNCTION_END(GLboolean, IsSampler, sampler)
@@ -357,7 +358,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniformMatrix4x3fv, GLuint program, G
DECLARE_GL_FUNCTION_STUB_HEAD(void, ValidateProgramPipeline, GLuint pipeline) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ValidateProgramPipeline, pipeline)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetProgramPipelineInfoLog, GLuint pipeline, GLsizei bufSize, GLsizei* length, GLchar* infoLog) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetProgramPipelineInfoLog, pipeline, bufSize, length, infoLog)
DECLARE_GL_FUNCTION_HEAD(void, BindImageTexture, GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindImageTexture, unit, texture, level, layered, layer, access, format)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetBooleani_v, GLenum target, GLuint index, GLboolean* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetBooleani_v, target, index, data)
DECLARE_GL_FUNCTION_HEAD(void, GetBooleani_v, GLenum target, GLuint index, GLboolean* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetBooleani_v, target, index, data)
DECLARE_GL_FUNCTION_HEAD(void, MemoryBarrier, GLbitfield barriers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MemoryBarrier, barriers)
DECLARE_GL_FUNCTION_HEAD(void, MemoryBarrierByRegion, GLbitfield barriers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MemoryBarrierByRegion, barriers)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TexStorage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexStorage2DMultisample, target, samples, internalformat, width, height, fixedsamplelocations)
@@ -829,8 +830,8 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib3sv, GLuint index, const GLshort
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4Nbv, GLuint index, const GLbyte* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4Nbv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4Niv, GLuint index, const GLint* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4Niv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4Nsv, GLuint index, const GLshort* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4Nsv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4Nub, GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4Nub, index, x, y, z, w)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4Nubv, GLuint index, const GLubyte* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4Nubv, index, v)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttrib4Nub, GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttrib4Nub, index, x, y, z, w)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttrib4Nubv, GLuint index, const GLubyte* v) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttrib4Nubv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4Nuiv, GLuint index, const GLuint* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4Nuiv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4Nusv, GLuint index, const GLushort* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4Nusv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4bv, GLuint index, const GLbyte* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4bv, index, v)
@@ -839,11 +840,11 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4dv, GLuint index, const GLdoubl
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4iv, GLuint index, const GLint* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4iv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4s, GLuint index, GLshort x, GLshort y, GLshort z, GLshort w) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4s, index, x, y, z, w)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4sv, GLuint index, const GLshort* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4sv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4ubv, GLuint index, const GLubyte* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4ubv, index, v)
DECLARE_GL_FUNCTION_HEAD(void, VertexAttrib4ubv, GLuint index, const GLubyte* v) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexAttrib4ubv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4uiv, GLuint index, const GLuint* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4uiv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4usv, GLuint index, const GLushort* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttrib4usv, index, v)
DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveRestartIndex, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PrimitiveRestartIndex, index)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetActiveUniformName, GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetActiveUniformName, program, uniformIndex, bufSize, length, uniformName)
DECLARE_GL_FUNCTION_HEAD(void, GetActiveUniformName, GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetActiveUniformName, program, uniformIndex, bufSize, length, uniformName)
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsBaseVertex, GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount, const GLint* basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsBaseVertex, mode, count, type, indices, drawcount, basevertex)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProvokingVertex, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProvokingVertex, mode)
DECLARE_GL_FUNCTION_HEAD(void, TexImage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage2DMultisample, target, samples, internalformat, width, height, fixedsamplelocations)
@@ -1489,9 +1490,9 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, Vertex3xvOES, const GLfixed* coords) DECLARE
DECLARE_GL_FUNCTION_STUB_HEAD(void, Vertex4xOES, GLfixed x, GLfixed y, GLfixed z) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Vertex4xOES, x, y, z)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Vertex4xvOES, const GLfixed* coords) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Vertex4xvOES, coords)
DECLARE_GL_FUNCTION_STUB_HEAD(GLbitfield, QueryMatrixxOES, GLfixed* mantissa, GLint* exponent) DECLARE_GL_FUNCTION_STUB_END(GLbitfield, QueryMatrixxOES, mantissa, exponent)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearDepthfOES, GLclampf depth) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearDepthfOES, depth)
DECLARE_GL_FUNCTION_HEAD(void, ClearDepthfOES, GLclampf depth) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearDepth, static_cast<GLclampd>(depth))
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClipPlanefOES, GLenum plane, const GLfloat* equation) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClipPlanefOES, plane, equation)
DECLARE_GL_FUNCTION_STUB_HEAD(void, DepthRangefOES, GLclampf n, GLclampf f) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DepthRangefOES, n, f)
DECLARE_GL_FUNCTION_HEAD(void, DepthRangefOES, GLclampf n, GLclampf f) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DepthRange, static_cast<GLclampd>(n), static_cast<GLclampd>(f))
DECLARE_GL_FUNCTION_STUB_HEAD(void, FrustumfOES, GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FrustumfOES, l, r, b, t, n, f)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetClipPlanefOES, GLenum plane, GLfloat* equation) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetClipPlanefOES, plane, equation)
DECLARE_GL_FUNCTION_STUB_HEAD(void, OrthofOES, GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, OrthofOES, l, r, b, t, n, f)
@@ -15,10 +15,144 @@
#include <MG_State/GLState/ErrorState/Error.h>
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToMG/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
#include <MG_Util/Converters/GLToMG/FramebufferEnumConverter.h>
namespace MobileGL::MG_Impl::GLImpl {
namespace {
Bool IsActiveBackendDirectVulkan() {
auto* activeBackend = MG_Backend::pActiveBackendObject.get();
return activeBackend != nullptr && activeBackend->GetBackendType() == BackendType::DirectVulkan;
}
Bool HasDistinctCompleteDepthStencilTextureAttachments(
const MG_State::GLState::FramebufferObject& framebufferObject) {
if (framebufferObject.GetExternalIndex() == 0) {
return false;
}
const auto& depthAttachment = framebufferObject.GetAttachment(FramebufferAttachmentType::Depth);
const auto& stencilAttachment = framebufferObject.GetAttachment(FramebufferAttachmentType::Stencil);
if (!depthAttachment.IsComplete() || !stencilAttachment.IsComplete() ||
!depthAttachment.IsTexture() || !stencilAttachment.IsTexture()) {
return false;
}
return depthAttachment.GetTexture().get() != stencilAttachment.GetTexture().get() ||
depthAttachment.GetTextureUploadTarget() != stencilAttachment.GetTextureUploadTarget() ||
depthAttachment.GetTextureLevel() != stencilAttachment.GetTextureLevel();
}
Bool HasCompleteRenderbufferAttachment(const MG_State::GLState::FramebufferObject& framebufferObject) {
if (framebufferObject.GetExternalIndex() == 0) {
return false;
}
for (const auto& attachment : framebufferObject.GetAllAttachmentObjects()) {
if (attachment.IsRenderbuffer() && attachment.IsComplete()) {
return true;
}
}
return false;
}
Bool IsUnsupportedFramebufferForDirectVulkan(
const MG_State::GLState::FramebufferObject& framebufferObject) {
return HasDistinctCompleteDepthStencilTextureAttachments(framebufferObject) ||
HasCompleteRenderbufferAttachment(framebufferObject);
}
void RecordUnsupportedFramebufferTextureAttachmentError(const char* functionName, const char* detail) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName, detail));
}
Bool ResolveRepresentableFramebufferTextureUploadTarget(const MG_State::GLState::ITextureObject& textureObject,
TextureUploadTarget& outUploadTarget) {
switch (textureObject.GetTarget()) {
case TextureTarget::Texture1D:
outUploadTarget = TextureUploadTarget::Texture1D;
return true;
case TextureTarget::Texture2D:
outUploadTarget = TextureUploadTarget::Texture2D;
return true;
case TextureTarget::TextureRectangle:
outUploadTarget = TextureUploadTarget::TextureRectangle;
return true;
case TextureTarget::Texture2DMultisample:
outUploadTarget = TextureUploadTarget::Texture2DMultisample;
return true;
default:
outUploadTarget = TextureUploadTarget::Unknown;
return false;
}
}
void AttachFramebufferTextureWithUploadTarget(const char* functionName, GLenum target, GLenum attachment,
GLuint texture, GLint level,
TextureUploadTarget textureUploadTarget) {
if (target == GL_FRAMEBUFFER) {
target = GL_DRAW_FRAMEBUFFER;
}
if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
AttachFramebufferTextureWithUploadTarget(functionName, target, GL_DEPTH_ATTACHMENT, texture, level,
textureUploadTarget);
AttachFramebufferTextureWithUploadTarget(functionName, target, GL_STENCIL_ATTACHMENT, texture, level,
textureUploadTarget);
return;
}
const FramebufferAttachmentType attachmentType = MG_Util::ConvertGLEnumToFramebufferAttachmentType(attachment);
const FramebufferTarget framebufferTarget = MG_Util::ConvertGLEnumToFramebufferTarget(target);
if (!FramebufferImpl::ValidateFramebufferAttachmentType(attachmentType)) return;
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return;
if (!TextureImpl::ValidateTextureName(texture, true)) return;
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
auto& framebufferObject = bindingSlot.GetBoundObject();
if (!framebufferObject) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName,
"Framebuffer target is bound to no framebuffer object."));
return;
}
if (texture == 0) {
framebufferObject->Detach(attachmentType);
return;
}
auto& textureObject = MG_State::pGLContext->GetTextureObject(texture);
if (!textureObject) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName,
std::format("Texture object {} is not valid.", texture)));
return;
}
const auto expectedTextureTarget = MG_Util::ConvertTextureUploadTargetToTextureTarget(textureUploadTarget);
if (expectedTextureTarget == TextureTarget::Unknown ||
textureObject->GetTarget() != expectedTextureTarget) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", functionName,
std::format("Attachment target {} does not match texture {} target {}.",
MG_Util::ConvertTextureUploadTargetToString(textureUploadTarget), texture,
MG_Util::ConvertTextureTargetToString(textureObject->GetTarget()))));
return;
}
framebufferObject->AttachTexture(attachmentType, textureObject, textureUploadTarget, level);
}
} // namespace
void BlitFramebuffer_Backend(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
MG_Backend::gBackendFunctionsTable.GL.BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1,
@@ -26,12 +160,53 @@ namespace MobileGL::MG_Impl::GLImpl {
}
void SampleMaski_State(GLuint maskNumber, GLbitfield mask) {
// TODO: implement
if (maskNumber != 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "SampleMaski_State",
"Only sample mask word 0 is currently supported."));
return;
}
MG_State::pGLContext->SetSampleMaskValue(static_cast<Uint32>(mask));
}
void RenderbufferStorageMultisample_State(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
GLsizei height) {
// TODO: implement
RenderbufferTarget rbTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
if (!FramebufferImpl::ValidateRenderbufferTarget(rbTarget)) return;
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(rbTarget);
auto& renderbufferObject = bindingSlot.GetBoundObject();
if (!renderbufferObject) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorageMultisample_State",
"Renderbuffer target is bound to no renderbuffer object."));
return;
}
TextureInternalFormat format = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
if (!TextureImpl::ValidateTextureInternalFormat(format)) return;
if (samples < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorageMultisample_State",
"Sample count must be non-negative."));
return;
}
if (width < 0 || height < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorageMultisample_State",
"Width and height must be non-negative."));
return;
}
renderbufferObject->AllocateStorage({width, height});
renderbufferObject->SetInternalFormat(format);
renderbufferObject->SetSamples(samples);
}
void RenderbufferStorage_State(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
@@ -56,14 +231,15 @@ namespace MobileGL::MG_Impl::GLImpl {
}
renderbufferObject->AllocateStorage({width, height});
renderbufferObject->SetInternalFormat(format);
renderbufferObject->SetSamples(0);
}
GLboolean IsRenderbuffer_State(GLuint renderbuffer) {
return MG_State::pGLContext->ValidateRenderbufferName(renderbuffer);
return MG_State::pGLContext->ValidateRenderbufferObject(renderbuffer);
}
GLboolean IsFramebuffer_State(GLuint framebuffer) {
return MG_State::pGLContext->ValidateFramebufferName(framebuffer);
return MG_State::pGLContext->ValidateFramebufferObject(framebuffer);
}
void GetFramebufferAttachmentParameteriv_State(GLenum target, GLenum attachment, GLenum pname, GLint* params) {
@@ -136,6 +312,26 @@ namespace MobileGL::MG_Impl::GLImpl {
: 0;
break;
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
if (attachmentObject != nullptr && attachmentObject->IsTexture() && attachmentObject->IsValid()) {
const GLenum glUploadTarget =
MG_Util::ConvertTextureUploadTargetToGLEnum(attachmentObject->GetTextureUploadTarget());
switch (glUploadTarget) {
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
*params = static_cast<GLint>(glUploadTarget);
break;
default:
*params = 0;
break;
}
} else {
*params = 0;
}
break;
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
*params = 0;
break;
@@ -174,12 +370,31 @@ namespace MobileGL::MG_Impl::GLImpl {
}
void FramebufferTextureLayer_State(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) {
// TODO: implement
if (texture == 0) {
const TextureUploadTarget detachTarget = TextureUploadTarget::Texture2D;
AttachFramebufferTextureWithUploadTarget(__func__, target, attachment, texture, level, detachTarget);
return;
}
static_cast<void>(layer);
RecordUnsupportedFramebufferTextureAttachmentError(
__func__,
"Layered framebuffer texture attachments are not represented by the current framebuffer attachment model.");
}
void FramebufferTexture3D_State(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level,
GLint zoffset) {
// TODO: implement
if (texture == 0) {
TextureUploadTarget textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(textarget);
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return;
AttachFramebufferTextureWithUploadTarget(__func__, target, attachment, texture, level, textureUploadTarget);
return;
}
static_cast<void>(zoffset);
RecordUnsupportedFramebufferTextureAttachmentError(
__func__,
"3D framebuffer texture slice attachments are not represented by the current framebuffer attachment model.");
}
void FramebufferTexture2D_State(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {
@@ -199,6 +414,11 @@ namespace MobileGL::MG_Impl::GLImpl {
if (!FramebufferImpl::ValidateFramebufferAttachmentType(attachmentType)) return;
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return;
if (!TextureImpl::ValidateTextureName(texture, true)) return;
TextureUploadTarget textureUploadTarget = TextureUploadTarget::Unknown;
if (texture != 0) {
textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(textarget);
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return;
}
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
auto& framebufferObject = bindingSlot.GetBoundObject();
@@ -224,15 +444,59 @@ namespace MobileGL::MG_Impl::GLImpl {
return;
}
framebufferObject->AttachTexture(attachmentType, textureObject, textureObject ? level : 0);
const auto expectedTextureTarget = MG_Util::ConvertTextureUploadTargetToTextureTarget(textureUploadTarget);
if (expectedTextureTarget == TextureTarget::Unknown ||
textureObject->GetTarget() != expectedTextureTarget) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", "FramebufferTexture2D_State",
std::format("Attachment target {} does not match texture {} target {}.",
MG_Util::ConvertGLEnumToString(textarget),
texture,
MG_Util::ConvertTextureTargetToString(textureObject->GetTarget()))));
return;
}
framebufferObject->AttachTexture(attachmentType, textureObject, textureUploadTarget, textureObject ? level : 0);
}
void FramebufferTexture1D_State(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {
// TODO: implement
TextureUploadTarget textureUploadTarget = TextureUploadTarget::Unknown;
if (texture != 0) {
textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(textarget);
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return;
} else {
textureUploadTarget = TextureUploadTarget::Texture1D;
}
AttachFramebufferTextureWithUploadTarget(__func__, target, attachment, texture, level, textureUploadTarget);
}
void FramebufferTexture_State(GLenum target, GLenum attachment, GLuint texture, GLint level) {
// TODO: implement
if (texture == 0) {
AttachFramebufferTextureWithUploadTarget(__func__, target, attachment, texture, level,
TextureUploadTarget::Texture2D);
return;
}
auto& textureObject = MG_State::pGLContext->GetTextureObject(texture);
if (!textureObject) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::format("Texture object {} is not valid.", texture)));
return;
}
TextureUploadTarget textureUploadTarget = TextureUploadTarget::Unknown;
if (!ResolveRepresentableFramebufferTextureUploadTarget(*textureObject, textureUploadTarget)) {
RecordUnsupportedFramebufferTextureAttachmentError(
__func__,
"Layered or multi-image framebuffer texture targets are not fully represented by the current framebuffer attachment model.");
return;
}
AttachFramebufferTextureWithUploadTarget(__func__, target, attachment, texture, level, textureUploadTarget);
}
void FramebufferRenderbuffer_State(GLenum target, GLenum attachment, GLenum renderbuffertarget,
@@ -246,7 +510,8 @@ namespace MobileGL::MG_Impl::GLImpl {
RenderbufferTarget rbTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(renderbuffertarget);
if (!FramebufferImpl::ValidateFramebufferAttachmentType(attachmentType)) return;
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return;
if (!FramebufferImpl::ValidateRenderbufferName(renderbuffer)) return;
if (!FramebufferImpl::ValidateRenderbufferTarget(rbTarget)) return;
if (!FramebufferImpl::ValidateRenderbufferName(renderbuffer, true)) return;
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
auto& framebufferObject = bindingSlot.GetBoundObject();
if (!framebufferObject) {
@@ -290,6 +555,12 @@ namespace MobileGL::MG_Impl::GLImpl {
// Get bound framebuffer
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
auto& fbo = bindingSlot.GetBoundObject();
if (!fbo) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "No framebuffer bound to draw target."));
return;
}
bool isDefaultFBO = (fbo == FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
static int existenceMap[(SizeT)FramebufferAttachmentType::FramebufferAttachmentTypeCount] = {-1};
@@ -308,20 +579,20 @@ namespace MobileGL::MG_Impl::GLImpl {
return;
}
if (isDefaultFBO && attType >= FramebufferAttachmentType::Color0 &&
attType <= FramebufferAttachmentType::Color31) {
if (isDefaultFBO && attType != FramebufferAttachmentType::None &&
(attType < FramebufferAttachmentType::FrontLeft || attType > FramebufferAttachmentType::BackRight)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", __func__,
std::format(
"FBO is default FBO, but bufs[{}] = {} is one of the `GL_COLOR_ATTACHMENTn` tokens.", i,
MG_Util::ConvertGLEnumToString(bufs[i]))));
std::format("FBO is default FBO, but bufs[{}] = {} is not `GL_NONE` or one of the default "
"framebuffer color buffer tokens.",
i, MG_Util::ConvertGLEnumToString(bufs[i]))));
return;
}
if (!isDefaultFBO && attType >= FramebufferAttachmentType::FrontLeft &&
attType <= FramebufferAttachmentType::BackRight) {
if (!isDefaultFBO && attType != FramebufferAttachmentType::None &&
(attType < FramebufferAttachmentType::Color0 || attType > FramebufferAttachmentType::Color31)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>(
@@ -388,6 +659,43 @@ namespace MobileGL::MG_Impl::GLImpl {
// Get bound framebuffer
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
auto& fbo = bindingSlot.GetBoundObject();
if (!fbo) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "No framebuffer bound to read target."));
return;
}
const Bool isDefaultFBO = (fbo == FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
if (isDefaultFBO && attType != FramebufferAttachmentType::None &&
(attType < FramebufferAttachmentType::FrontLeft || attType > FramebufferAttachmentType::BackRight)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", __func__,
std::format("Default framebuffer read buffer {} is not valid.", MG_Util::ConvertGLEnumToString(mode))));
return;
}
if (!isDefaultFBO && attType != FramebufferAttachmentType::None &&
(attType < FramebufferAttachmentType::Color0 || attType > FramebufferAttachmentType::Color31)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::format("Framebuffer object read buffer {} is not valid.",
MG_Util::ConvertGLEnumToString(mode))));
return;
}
if (!isDefaultFBO &&
static_cast<SizeT>(attType) >
static_cast<SizeT>(FramebufferAttachmentType::Color0) +
MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::format("Read buffer {} indicates a color buffer that does not exist "
"in the current GL context.",
MG_Util::ConvertGLEnumToString(mode))));
return;
}
fbo->SetReadBuffer(attType);
}
@@ -453,24 +761,35 @@ namespace MobileGL::MG_Impl::GLImpl {
// TODO: distinguish GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT and GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
// TODO: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER, GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER,
// GL_FRAMEBUFFER_UNSUPPORTED, GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
// additional GL_FRAMEBUFFER_UNSUPPORTED cases, GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
// GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS
return framebufferObject->CheckCompleteness() ? GL_FRAMEBUFFER_COMPLETE
: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
if (!framebufferObject->CheckCompleteness()) {
return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
}
if (IsActiveBackendDirectVulkan() &&
IsUnsupportedFramebufferForDirectVulkan(*framebufferObject)) {
return GL_FRAMEBUFFER_UNSUPPORTED;
}
return GL_FRAMEBUFFER_COMPLETE;
}
void BindRenderbuffer_State(GLenum target, GLuint renderbuffer) {
if (!FramebufferImpl::ValidateRenderbufferName(renderbuffer)) return;
if (!FramebufferImpl::ValidateRenderbufferName(renderbuffer, true)) return;
RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
if (!FramebufferImpl::ValidateRenderbufferTarget(renderbufferTarget)) return;
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(renderbufferTarget);
if (renderbuffer == 0) {
bindingSlot.Bind(nullptr);
return;
}
Bool doesRenderbufferCreated = MG_State::pGLContext->ValidateRenderbufferObject(renderbuffer);
if (!doesRenderbufferCreated) {
MG_State::pGLContext->CreateRenderbufferObject(renderbuffer);
}
auto& renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer);
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(renderbufferTarget);
bindingSlot.Bind(renderbufferObject);
}
@@ -567,7 +886,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_Backend::gBackendFunctionsTable.GL.ClearBufferiv(buffer, drawbuffer, value);
}
void ReadPixels_State(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
Bool ReadPixels_State(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
TextureInputFormat textureInputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format);
TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type);
@@ -576,7 +895,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"Width and height must be non-negative"));
return;
return false;
}
// Validate format
@@ -584,7 +903,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid format"));
return;
return false;
}
// Validate type
@@ -592,7 +911,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Invalid pixel data type"));
return;
return false;
}
// Get bound framebuffer
@@ -603,7 +922,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"No framebuffer bound to read target"));
return;
return false;
}
// Check framebuffer completeness
@@ -611,7 +930,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidFramebufferOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", "Framebuffer is incomplete"));
return;
return false;
}
// Check for required buffers
@@ -621,7 +940,7 @@ namespace MobileGL::MG_Impl::GLImpl {
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"No stencil buffer for stencil index format"));
return;
return false;
}
} else if (textureInputFormat == TextureInputFormat::DepthComponent) {
if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Depth).IsValid()) {
@@ -629,7 +948,7 @@ namespace MobileGL::MG_Impl::GLImpl {
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"No depth buffer for depth component format"));
return;
return false;
}
} else if (textureInputFormat == TextureInputFormat::DepthStencil) {
if (!framebufferObject->GetAttachment(FramebufferAttachmentType::Depth).IsValid() ||
@@ -638,7 +957,7 @@ namespace MobileGL::MG_Impl::GLImpl {
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"No depth/stencil buffer for depth-stencil format"));
return;
return false;
}
// Validate type for depth/stencil
@@ -647,7 +966,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"Invalid type for depth-stencil format"));
return;
return false;
}
}
@@ -661,7 +980,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"Pixel pack buffer is currently mapped"));
return;
return false;
}
// Check alignment
@@ -671,7 +990,7 @@ namespace MobileGL::MG_Impl::GLImpl {
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"Pixel data not aligned for pixel pack buffer"));
return;
return false;
}
}
@@ -683,9 +1002,11 @@ namespace MobileGL::MG_Impl::GLImpl {
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"ReadPixels not supported for multisampled framebuffers"));
return;
return false;
}
}
return true;
}
void ReadPixels_Backend(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
@@ -694,7 +1015,7 @@ namespace MobileGL::MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
ReadPixels_State(x, y, width, height, format, type, pixels);
if (!ReadPixels_State(x, y, width, height, format, type, pixels)) return;
ReadPixels_Backend(x, y, width, height, format, type, pixels);
}
File diff suppressed because it is too large Load Diff
@@ -13,7 +13,10 @@ namespace MobileGL::MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
const GLubyte* GetString(GLenum name);
const GLubyte* GetStringi(GLenum name, GLuint index);
void GetBooleanv(GLenum pname, GLboolean* params);
void GetFloatv(GLenum pname, GLfloat* params);
void GetIntegerv(GLenum pname, GLint* params);
void GetInteger64v(GLenum pname, GLint64* params);
void GetIntegeri_v(GLenum target, GLuint index, GLint* data);
void GetInteger64i_v(GLenum target, GLuint index, GLint64* data);
GLenum GetError();
+232 -125
View File
@@ -16,6 +16,10 @@
#include <MG_Backend/BackendObjects.h>
namespace MobileGL::MG_Impl::GLImpl {
static GLint BoolToGLInt(bool value) {
return value ? GL_TRUE : GL_FALSE;
}
static bool CheckShaderNameValidity(Uint shader) {
if (shader == 0 || !MG_State::pGLContext->ValidateShaderName(shader)) {
MG_State::pGLContext->RecordError(
@@ -80,6 +84,16 @@ namespace MobileGL::MG_Impl::GLImpl {
if (length) *length = sz;
}
bool RecordInvalidUniformLocationError(const char* functionName, GLint location, const String& targetDescription) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName,
"location " + std::to_string(location) +
" does not correspond to a valid uniform variable location for " +
targetDescription + "."));
return false;
}
void AttachShader_State(GLuint program, GLuint shader) {
auto& programObject = TryToGetProgramObject(program);
if (!programObject) return;
@@ -188,9 +202,10 @@ namespace MobileGL::MG_Impl::GLImpl {
std::to_string(program) + "."));
return;
}
if (type != nullptr) *type = programObject->GetAttribType(index);
if (size != nullptr) *size = programObject->GetActiveAttribArraySize(index);
if (type != nullptr) *type = programObject->GetActiveAttribType(index);
if (bufSize == 0) return;
auto& attribName = programObject->GetAttribName(index);
auto& attribName = programObject->GetActiveAttribName(index);
CopyStr(bufSize, length, name, attribName.c_str(), (GLsizei)attribName.length());
}
@@ -216,13 +231,38 @@ namespace MobileGL::MG_Impl::GLImpl {
std::to_string(program) + "."));
return;
}
if (type != nullptr) *type = programObject->GetUniformType(index);
if (size != nullptr) *size = programObject->GetActiveUniformArraySize(index);
if (type != nullptr) *type = programObject->GetActiveUniformType(index);
if (bufSize == 0) return;
auto& uniformName = programObject->GetUniformName(index);
auto& uniformName = programObject->GetActiveUniformName(index);
CopyStr(bufSize, length, name, uniformName.c_str(), (GLsizei)uniformName.length());
}
void GetUniformIndices_State(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames,
GLuint* uniformIndices) {
if (uniformCount < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"uniformCount " + std::to_string(uniformCount) + " is less than 0."));
return;
}
auto& programObject = TryToGetProgramObject(program);
if (!programObject || !programObject->GetLinkStatus()) return;
if (uniformCount == 0 || uniformNames == nullptr || uniformIndices == nullptr) return;
for (GLsizei i = 0; i < uniformCount; ++i) {
const char* uniformName = uniformNames[i];
if (uniformName == nullptr) {
uniformIndices[i] = GL_INVALID_INDEX;
continue;
}
const Int uniformIndex = programObject->GetActiveUniformIndex(uniformName);
uniformIndices[i] = uniformIndex >= 0 ? static_cast<GLuint>(uniformIndex) : GL_INVALID_INDEX;
}
}
void GetAttachedShaders_State(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders) {
if (maxCount < 0) {
MG_State::pGLContext->RecordError(
@@ -268,7 +308,7 @@ namespace MobileGL::MG_Impl::GLImpl {
break;
case GL_INFO_LOG_LENGTH: {
const auto& log = programObject->GetInfoLog();
*params = (GLint)log.length();
*params = log.empty() ? 0 : static_cast<GLint>(log.length()) + 1;
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params);
break;
}
@@ -287,7 +327,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params);
break;
case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
*params = programObject->GetActiveAttributesMaxLength();
*params = programObject->GetActiveAttributesMaxLength() + 1;
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params);
break;
case GL_ACTIVE_UNIFORMS:
@@ -295,7 +335,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params);
break;
case GL_ACTIVE_UNIFORM_MAX_LENGTH:
*params = programObject->GetUniformMaxLength();
*params = programObject->GetUniformMaxLength() + 1;
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params);
break;
case GL_ACTIVE_UNIFORM_BLOCKS: // GL >= 3.1
@@ -303,22 +343,21 @@ namespace MobileGL::MG_Impl::GLImpl {
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params);
break;
case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: // ditto.
*params = programObject->GetActiveUniformBlocksMaxNameLength();
*params = programObject->GetActiveUniformBlocksMaxNameLength() + 1;
MGLOG_D("%s: %s = %d", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), *params);
break;
case GL_COMPUTE_WORK_GROUP_SIZE: { // GL >= 4.3
auto getProgramiv = MG_Backend::gBackendFunctionsTable.GL.GetProgramiv;
if (!getProgramiv) {
params[0] = 1;
params[1] = 1;
params[2] = 1;
if (!programObject->GetLinkStatus()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not support program integer queries."));
std::to_string(program) +
" is not a program object that has been linked."));
return;
}
getProgramiv(program, pname, params);
params[0] = static_cast<GLint>(programObject->GetComputeLocalSize(0));
params[1] = static_cast<GLint>(programObject->GetComputeLocalSize(1));
params[2] = static_cast<GLint>(programObject->GetComputeLocalSize(2));
MGLOG_D("%s: %s = (%d, %d, %d)", __func__, MG_Util::ConvertGLEnumToString(pname).c_str(), params[0],
params[1], params[2]);
break;
@@ -423,25 +462,13 @@ namespace MobileGL::MG_Impl::GLImpl {
}
// Check if location is valid
if (location < 0 || location > programObject->GetMaxUniformLocation()) {
if (!programObject->IsValidUniformLocation(location)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) +
" does not correspond to a valid uniform variable location "
"for the specified program object."));
return;
}
// Check if the location corresponds to an active uniform
const auto& uniformName = programObject->GetUniformName(location);
if (uniformName.empty()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) +
" does not correspond to a valid uniform variable location "
"for the specified program object."));
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) +
" does not correspond to a valid uniform variable location for the specified program object."));
return;
}
@@ -468,12 +495,64 @@ namespace MobileGL::MG_Impl::GLImpl {
// TODO: handle 1i variant as texture unit
}
template <typename T>
void GetUniformScalar_State(GLuint program, GLint location, T* params) {
auto& programObject = TryToGetProgramObject(program);
if (!programObject) return;
if (!programObject->GetLinkStatus()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
std::to_string(program) + " has not been successfully linked."));
return;
}
if (!programObject->IsValidUniformLocation(location)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) +
" does not correspond to a valid uniform variable location for the specified program object."));
return;
}
if (programObject->IsUniformOpaqueAtLocation(location)) {
const Int unit = std::max(programObject->GetUniformSamplerOrImageUnitIndex(location), 0);
*params = static_cast<T>(unit);
return;
}
auto offset = programObject->GetUniformOffset(location);
auto size = programObject->GetUniformSizesInBytes(location);
char* pUBO = static_cast<char*>(programObject->MapUBO());
auto* ttype = programObject->GetUniformTType(location);
if constexpr (std::is_same_v<T, GLfloat>) {
if (ttype->isMatrix() && ttype->getMatrixCols() == 3) {
auto* pBase = pUBO + offset;
for (int i = 0; i < ttype->getMatrixRows(); i++) {
Memcpy(reinterpret_cast<char*>(params) + ttype->getMatrixCols() * sizeof(GLfloat) * i,
pBase + 4 * sizeof(GLfloat) * i, ttype->getMatrixCols() * sizeof(GLfloat));
}
return;
}
}
Memcpy(params, pUBO + offset, size);
}
void GetUniformfv_State(GLuint program, GLint location, GLfloat* params) {
GetUniform_State(program, location, params);
GetUniformScalar_State(program, location, params);
}
void GetUniformiv_State(GLuint program, GLint location, GLint* params) {
GetUniform_State(program, location, params);
GetUniformScalar_State(program, location, params);
}
void GetUniformuiv_State(GLuint program, GLint location, GLuint* params) {
GetUniformScalar_State(program, location, params);
}
GLboolean IsProgram_State(GLuint program) {
@@ -585,18 +664,11 @@ namespace MobileGL::MG_Impl::GLImpl {
return;
}
if (location > programObject->GetMaxUniformLocation() || location < -1) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) +
" is an invalid uniform location for the current program "
"object and location " +
std::to_string(location) + " is not equal to -1."));
return;
}
for (GLint offset = 0; offset < count; offset++) {
if (!programObject->IsValidUniformLocation(location + offset)) {
RecordInvalidUniformLocationError(__func__, location + offset, "the current program object");
return;
}
Uniform_State<ItemCount>(*programObject, location + offset, value + offset * ItemCount);
}
}
@@ -616,17 +688,12 @@ namespace MobileGL::MG_Impl::GLImpl {
return;
}
if (location > programObject->GetMaxUniformLocation() || location < -1) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) +
" is an invalid uniform location for program " +
std::to_string(program) + "."));
return;
}
for (GLint offset = 0; offset < count; offset++) {
if (!programObject->IsValidUniformLocation(location + offset)) {
RecordInvalidUniformLocationError(__func__, location + offset,
"program " + std::to_string(program));
return;
}
Uniform_State<ItemCount>(*programObject, location + offset, value + offset * ItemCount);
}
}
@@ -744,19 +811,12 @@ namespace MobileGL::MG_Impl::GLImpl {
return;
}
if (location > programObject->GetMaxUniformLocation() || location < -1) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) +
" is an invalid uniform location for the current program "
"object and location " +
std::to_string(location) + " is not equal to -1."));
return;
}
// For matrix uniforms, we handle each matrix individually
for (GLint i = 0; i < count; i++) {
if (!programObject->IsValidUniformLocation(location + i)) {
RecordInvalidUniformLocationError(__func__, location + i, "the current program object");
return;
}
if (transpose == GL_TRUE) {
// Transpose the matrix before uploading
GLfloat transposedMatrix[4];
@@ -782,20 +842,13 @@ namespace MobileGL::MG_Impl::GLImpl {
return;
}
if (location > programObject->GetMaxUniformLocation() || location < -1) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) +
" is an invalid uniform location for the current program "
"object and location " +
std::to_string(location) + " is not equal to -1."));
return;
}
// For matrix uniforms, we handle each matrix individually
// Handle padding in mat3 correctly!!
for (GLint i = 0; i < count; i++) {
if (!programObject->IsValidUniformLocation(location + i)) {
RecordInvalidUniformLocationError(__func__, location + i, "the current program object");
return;
}
if (transpose == GL_TRUE) {
// Transpose the matrix before uploading
GLfloat transposedMatrix[9];
@@ -825,19 +878,12 @@ namespace MobileGL::MG_Impl::GLImpl {
return;
}
if (location > programObject->GetMaxUniformLocation() || location < -1) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) +
" is an invalid uniform location for the current program "
"object and location " +
std::to_string(location) + " is not equal to -1."));
return;
}
// For matrix uniforms, we handle each matrix individually
for (GLint i = 0; i < count; i++) {
if (!programObject->IsValidUniformLocation(location + i)) {
RecordInvalidUniformLocationError(__func__, location + i, "the current program object");
return;
}
if (transpose == GL_TRUE) {
// Transpose the matrix before uploading
GLfloat transposedMatrix[16];
@@ -865,17 +911,11 @@ namespace MobileGL::MG_Impl::GLImpl {
return;
}
if (location > programObject->GetMaxUniformLocation() || location < -1) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) +
" is an invalid uniform location for program " +
std::to_string(program) + "."));
return;
}
for (GLint i = 0; i < count; i++) {
if (!programObject->IsValidUniformLocation(location + i)) {
RecordInvalidUniformLocationError(__func__, location + i, "program " + std::to_string(program));
return;
}
if (transpose == GL_TRUE) {
GLfloat transposedMatrix[4];
TransposeMatrix2x2(value + i * 4, transposedMatrix);
@@ -901,17 +941,11 @@ namespace MobileGL::MG_Impl::GLImpl {
return;
}
if (location > programObject->GetMaxUniformLocation() || location < -1) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) +
" is an invalid uniform location for program " +
std::to_string(program) + "."));
return;
}
for (GLint i = 0; i < count; i++) {
if (!programObject->IsValidUniformLocation(location + i)) {
RecordInvalidUniformLocationError(__func__, location + i, "program " + std::to_string(program));
return;
}
if (transpose == GL_TRUE) {
GLfloat transposedMatrix[9];
TransposeMatrix3x3(value + i * 9, transposedMatrix);
@@ -941,17 +975,11 @@ namespace MobileGL::MG_Impl::GLImpl {
return;
}
if (location > programObject->GetMaxUniformLocation() || location < -1) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"location " + std::to_string(location) +
" is an invalid uniform location for program " +
std::to_string(program) + "."));
return;
}
for (GLint i = 0; i < count; i++) {
if (!programObject->IsValidUniformLocation(location + i)) {
RecordInvalidUniformLocationError(__func__, location + i, "program " + std::to_string(program));
return;
}
if (transpose == GL_TRUE) {
GLfloat transposedMatrix[16];
TransposeMatrix4x4(value + i * 16, transposedMatrix);
@@ -1033,22 +1061,52 @@ namespace MobileGL::MG_Impl::GLImpl {
break;
}
case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: {
// TODO: deduct global ubo?
*params = programObject->GetActiveUniformBlocksCount();
*params = programObject->GetUniformBlockActiveUniformCount(uniformBlockIndex);
MGLOG_D("%s: GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS = %d", __func__, *params);
break;
}
case GL_UNIFORM_BLOCK_BINDING: {
// TODO
MGLOG_D("%s: GL_UNIFORM_BLOCK_BINDING = <TODO>", __func__, *params);
*params = static_cast<GLint>(programObject->GetUniformBlockBinding(uniformBlockIndex));
MGLOG_D("%s: GL_UNIFORM_BLOCK_BINDING = %d", __func__, *params);
break;
}
case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
*params = BoolToGLInt(programObject->IsUniformBlockReferencedByStage(uniformBlockIndex, EShLangVertex));
MGLOG_D("%s: GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER = %d", __func__, *params);
break;
case GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER:
*params =
BoolToGLInt(programObject->IsUniformBlockReferencedByStage(uniformBlockIndex, EShLangTessControl));
MGLOG_D("%s: GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER = %d", __func__, *params);
break;
case GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER:
*params =
BoolToGLInt(programObject->IsUniformBlockReferencedByStage(uniformBlockIndex, EShLangTessEvaluation));
MGLOG_D("%s: GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER = %d", __func__, *params);
break;
case GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER:
*params = BoolToGLInt(programObject->IsUniformBlockReferencedByStage(uniformBlockIndex, EShLangGeometry));
MGLOG_D("%s: GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER = %d", __func__, *params);
break;
case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
*params = BoolToGLInt(programObject->IsUniformBlockReferencedByStage(uniformBlockIndex, EShLangFragment));
MGLOG_D("%s: GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER = %d", __func__, *params);
break;
case GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER:
*params = BoolToGLInt(programObject->IsUniformBlockReferencedByStage(uniformBlockIndex, EShLangCompute));
MGLOG_D("%s: GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER = %d", __func__, *params);
break;
case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: {
GLint uniformIndexCount = 0;
for (Uint uniformIndex = 0; uniformIndex < programObject->GetUniformCount(); ++uniformIndex) {
if (programObject->GetActiveUniformBlockIndex(uniformIndex) != static_cast<Int>(uniformBlockIndex)) {
continue;
}
params[uniformIndexCount++] = static_cast<GLint>(uniformIndex);
}
MGLOG_D("%s: GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES count = %d", __func__, uniformIndexCount);
break;
}
default:
MGLOG_E("%s: unknown pname = %p %s", __func__, pname, MG_Util::ConvertGLEnumToString(pname).c_str());
MG_State::pGLContext->RecordError(
@@ -1084,7 +1142,7 @@ namespace MobileGL::MG_Impl::GLImpl {
const auto& name = programObject->GetUniformBlockName(uniformBlockIndex);
CopyStr(bufSize, length, uniformBlockName, name.c_str(), (GLsizei)name.length());
MGLOG_D("%s: \"%s\" at uniformBlockIndex %02d, length = %d", __func__, uniformBlockName, uniformBlockIndex,
*length);
length ? *length : 0);
}
void BindFragDataLocation_State(GLuint program, GLuint colorNumber, const char* name) {
@@ -1166,6 +1224,16 @@ namespace MobileGL::MG_Impl::GLImpl {
GetActiveUniform_State(program, index, bufSize, length, size, type, name);
}
void GetActiveUniformName(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length,
GLchar* uniformName) {
GetActiveUniform_State(program, uniformIndex, bufSize, length, nullptr, nullptr, uniformName);
}
void GetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames,
GLuint* uniformIndices) {
GetUniformIndices_State(program, uniformCount, uniformNames, uniformIndices);
}
void GetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders) {
GetAttachedShaders_State(program, maxCount, count, shaders);
}
@@ -1206,6 +1274,10 @@ namespace MobileGL::MG_Impl::GLImpl {
GetUniformiv_State(program, location, params);
}
void GetUniformuiv(GLuint program, GLint location, GLuint* params) {
GetUniformuiv_State(program, location, params);
}
GLboolean IsProgram(GLuint program) {
return IsProgram_State(program);
}
@@ -1263,6 +1335,25 @@ namespace MobileGL::MG_Impl::GLImpl {
Uniform4iv(location, 1, v);
}
void Uniform1ui(GLint location, GLuint v0) {
Uniform1uiv(location, 1, &v0);
}
void Uniform2ui(GLint location, GLuint v0, GLuint v1) {
GLuint v[] = {v0, v1};
Uniform2uiv(location, 1, v);
}
void Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) {
GLuint v[] = {v0, v1, v2};
Uniform3uiv(location, 1, v);
}
void Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) {
GLuint v[] = {v0, v1, v2, v3};
Uniform4uiv(location, 1, v);
}
void Uniform1fv(GLint location, GLsizei count, const GLfloat* value) {
Uniform1fv_State(location, count, value);
}
@@ -1295,6 +1386,22 @@ namespace MobileGL::MG_Impl::GLImpl {
Uniform4iv_State(location, count, value);
}
void Uniform1uiv(GLint location, GLsizei count, const GLuint* value) {
Uniformv_State<1>(location, count, value);
}
void Uniform2uiv(GLint location, GLsizei count, const GLuint* value) {
Uniformv_State<2>(location, count, value);
}
void Uniform3uiv(GLint location, GLsizei count, const GLuint* value) {
Uniformv_State<3>(location, count, value);
}
void Uniform4uiv(GLint location, GLsizei count, const GLuint* value) {
Uniformv_State<4>(location, count, value);
}
void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
UniformMatrix2fv_State(location, count, transpose, value);
}
@@ -22,6 +22,10 @@ namespace MobileGL::MG_Impl::GLImpl {
GLchar* name);
void GetActiveUniform(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type,
GLchar* name);
void GetActiveUniformName(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length,
GLchar* uniformName);
void GetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames,
GLuint* uniformIndices);
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);
@@ -32,6 +36,7 @@ namespace MobileGL::MG_Impl::GLImpl {
GLint GetUniformLocation(GLuint program, const GLchar* name);
void GetUniformfv(GLuint program, GLint location, GLfloat* params);
void GetUniformiv(GLuint program, GLint location, GLint* params);
void GetUniformuiv(GLuint program, GLint location, GLuint* params);
GLboolean IsProgram(GLuint program);
GLboolean IsShader(GLuint shader);
void LinkProgram(GLuint program);
@@ -45,6 +50,10 @@ namespace MobileGL::MG_Impl::GLImpl {
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 Uniform1ui(GLint location, GLuint v0);
void Uniform2ui(GLint location, GLuint v0, GLuint v1);
void Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2);
void Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint 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);
@@ -53,6 +62,10 @@ namespace MobileGL::MG_Impl::GLImpl {
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 Uniform1uiv(GLint location, GLsizei count, const GLuint* value);
void Uniform2uiv(GLint location, GLsizei count, const GLuint* value);
void Uniform3uiv(GLint location, GLsizei count, const GLuint* value);
void Uniform4uiv(GLint location, GLsizei count, const GLuint* 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);
@@ -14,6 +14,32 @@
#include <MG_Util/Converters/MGToStr/RenderStateEnumConverter.h>
namespace MobileGL::MG_Impl::GLImpl {
static Float ClampUnitFloat(GLfloat value) {
return std::clamp(static_cast<Float>(value), 0.0f, 1.0f);
}
static Bool ValidateIndexedBlendCapability(GLenum target, GLuint index, const char* functionName) {
if (target != GL_BLEND) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName,
"Only GL_BLEND is supported for indexed capability state."));
return false;
}
if (index >= MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", functionName,
"Buffer index " + std::to_string(index) + " is out of range. Max supported is " +
std::to_string(MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS - 1) + "."));
return false;
}
return true;
}
static Bool TryConvertBlendEquation(GLenum mode, const char* functionName,
::MobileGL::BlendEquation& outEquation) {
outEquation = MG_Util::ConvertGLEnumToBlendEquation(mode);
@@ -27,6 +53,43 @@ namespace MobileGL::MG_Impl::GLImpl {
return false;
}
static Bool TryDecodeStencilFace(GLenum face, const char* functionName, Bool& applyFront, Bool& applyBack) {
switch (face) {
case GL_FRONT:
applyFront = true;
applyBack = false;
return true;
case GL_BACK:
applyFront = false;
applyBack = true;
return true;
case GL_FRONT_AND_BACK:
applyFront = true;
applyBack = true;
return true;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName,
"Stencil face enum " + MG_Util::ConvertGLEnumToString(face) +
" is not supported."));
return false;
}
}
static Bool TryConvertStencilOperation(GLenum value, const char* functionName, const char* paramName,
StencilOperation& outOperation) {
outOperation = MG_Util::ConvertGLEnumToStencilOperation(value);
if (outOperation != StencilOperation::Unknown) return true;
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName,
String(paramName) + " enum " + MG_Util::ConvertGLEnumToString(value) +
" is not supported."));
return false;
}
void Viewport_State(GLint x, GLint y, GLsizei width, GLsizei height) {
if (width < 0 || height < 0) {
MG_State::pGLContext->RecordError(ErrorCode::InvalidValue,
@@ -39,27 +102,74 @@ namespace MobileGL::MG_Impl::GLImpl {
}
void StencilOpSeparate_State(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {
// TODO: implement
Bool applyFront = false;
Bool applyBack = false;
if (!TryDecodeStencilFace(face, "StencilOpSeparate_State", applyFront, applyBack)) return;
StencilOperation failOp = StencilOperation::Unknown;
StencilOperation depthFailOp = StencilOperation::Unknown;
StencilOperation depthPassOp = StencilOperation::Unknown;
if (!TryConvertStencilOperation(sfail, "StencilOpSeparate_State", "sfail", failOp) ||
!TryConvertStencilOperation(dpfail, "StencilOpSeparate_State", "dpfail", depthFailOp) ||
!TryConvertStencilOperation(dppass, "StencilOpSeparate_State", "dppass", depthPassOp)) {
return;
}
if (applyFront) {
MG_State::pGLContext->SetStencilOp(StencilFace::Front, failOp, depthFailOp, depthPassOp);
}
if (applyBack) {
MG_State::pGLContext->SetStencilOp(StencilFace::Back, failOp, depthFailOp, depthPassOp);
}
}
void StencilOp_State(GLenum fail, GLenum zfail, GLenum zpass) {
// TODO: implement
StencilOpSeparate_State(GL_FRONT_AND_BACK, fail, zfail, zpass);
}
void StencilMaskSeparate_State(GLenum face, GLuint mask) {
// TODO: implement
Bool applyFront = false;
Bool applyBack = false;
if (!TryDecodeStencilFace(face, "StencilMaskSeparate_State", applyFront, applyBack)) return;
if (applyFront) {
MG_State::pGLContext->SetStencilMask(StencilFace::Front, mask);
}
if (applyBack) {
MG_State::pGLContext->SetStencilMask(StencilFace::Back, mask);
}
}
void StencilMask_State(GLuint mask) {
// TODO: implement
StencilMaskSeparate_State(GL_FRONT_AND_BACK, mask);
}
void StencilFuncSeparate_State(GLenum face, GLenum func, GLint ref, GLuint mask) {
// TODO: implement
Bool applyFront = false;
Bool applyBack = false;
if (!TryDecodeStencilFace(face, "StencilFuncSeparate_State", applyFront, applyBack)) return;
DepthTestFunc depthFunc = MG_Util::ConvertGLEnumToDepthTestFunc(func);
if (depthFunc == DepthTestFunc::Unknown) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "StencilFuncSeparate_State",
"Stencil func enum " + MG_Util::ConvertGLEnumToString(func) +
" is not supported."));
return;
}
const Int clampedRef = std::max(ref, 0);
if (applyFront) {
MG_State::pGLContext->SetStencilFunc(StencilFace::Front, depthFunc, clampedRef, mask);
}
if (applyBack) {
MG_State::pGLContext->SetStencilFunc(StencilFace::Back, depthFunc, clampedRef, mask);
}
}
void StencilFunc_State(GLenum func, GLint ref, GLuint mask) {
// TODO: implement
StencilFuncSeparate_State(GL_FRONT_AND_BACK, func, ref, mask);
}
void Scissor_State(GLint x, GLint y, GLsizei width, GLsizei height) {
@@ -74,11 +184,11 @@ namespace MobileGL::MG_Impl::GLImpl {
}
void SampleCoverage_State(GLfloat value, GLboolean invert) {
// TODO: implement
MG_State::pGLContext->SetSampleCoverage(std::clamp(static_cast<Float>(value), 0.0f, 1.0f), invert == GL_TRUE);
}
void PolygonOffset_State(GLfloat factor, GLfloat units) {
// TODO: implement
MG_State::pGLContext->SetPolygonOffset(static_cast<Float>(factor), static_cast<Float>(units));
}
void PolygonMode_State(GLenum face, GLenum mode) {
@@ -86,7 +196,15 @@ namespace MobileGL::MG_Impl::GLImpl {
}
void PointSize_State(GLfloat size) {
// TODO: implement
if (size <= 0.0f) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "PointSize_State",
"Point size must be greater than zero."));
return;
}
MG_State::pGLContext->SetPointSize(static_cast<Float>(size));
}
void PointParameterf_State(GLenum pname, GLfloat param) {
@@ -114,14 +232,36 @@ namespace MobileGL::MG_Impl::GLImpl {
}
void LogicOp_State(GLenum opcode) {
// TODO: implement
LogicOperation logicOp = MG_Util::ConvertGLEnumToLogicOperation(opcode);
if (logicOp == LogicOperation::Unknown) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "LogicOp_State",
"Logic op enum " + MG_Util::ConvertGLEnumToString(opcode) +
" is not supported."));
return;
}
MG_State::pGLContext->SetLogicOp(logicOp);
}
void LineWidth_State(GLfloat width) {
// TODO: implement
if (width <= 0.0f) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "LineWidth_State",
"Line width must be greater than zero."));
return;
}
MG_State::pGLContext->SetLineWidth(static_cast<Float>(width));
}
GLboolean IsEnabledi_State(GLenum target, GLuint index) {
if (!ValidateIndexedBlendCapability(target, index, "IsEnabledi_State")) {
return GL_FALSE;
}
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
if (capInput == CapabilityInput::Unknown) {
MG_State::pGLContext->RecordError(
@@ -135,6 +275,18 @@ namespace MobileGL::MG_Impl::GLImpl {
return MG_State::pGLContext->IsCapabilityEnabledIndexed(capInput, index) ? GL_TRUE : GL_FALSE;
}
void GetBooleani_v_State(GLenum target, GLuint index, GLboolean* data) {
if (!data) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetBooleani_v_State",
"data pointer cannot be null."));
return;
}
*data = IsEnabledi_State(target, index);
}
GLboolean IsEnabled_State(GLenum cap) {
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
if (capInput == CapabilityInput::Unknown) {
@@ -197,7 +349,8 @@ namespace MobileGL::MG_Impl::GLImpl {
}
void DepthRange_State(GLclampd near_val, GLclampd far_val) {
// TODO: implement
MG_State::pGLContext->SetDepthRange(
FloatVec2(ClampUnitFloat(static_cast<GLfloat>(near_val)), ClampUnitFloat(static_cast<GLfloat>(far_val))));
}
void DepthMask_State(GLboolean flag) {
@@ -289,7 +442,8 @@ namespace MobileGL::MG_Impl::GLImpl {
}
void BlendColor_State(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
// TODO: implement
MG_State::pGLContext->SetBlendColor(
FloatVec4(ClampUnitFloat(red), ClampUnitFloat(green), ClampUnitFloat(blue), ClampUnitFloat(alpha)));
}
void ClearStencil_State(GLint s) {
@@ -359,6 +513,10 @@ namespace MobileGL::MG_Impl::GLImpl {
}
void Disablei_State(GLenum target, GLuint index) {
if (!ValidateIndexedBlendCapability(target, index, "Disablei_State")) {
return;
}
auto capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
if (capInput == CapabilityInput::Unknown) {
MG_State::pGLContext->RecordError(
@@ -373,6 +531,10 @@ namespace MobileGL::MG_Impl::GLImpl {
}
void Enablei_State(GLenum target, GLuint index) {
if (!ValidateIndexedBlendCapability(target, index, "Enablei_State")) {
return;
}
auto capInput = MG_Util::ConvertGLEnumToCapabilityInput(target);
if (capInput == CapabilityInput::Unknown) {
MG_State::pGLContext->RecordError(
@@ -403,6 +565,10 @@ namespace MobileGL::MG_Impl::GLImpl {
BlendFuncSeparatei_State(buf, srcRGB, dstRGB, srcAlpha, dstAlpha);
}
void GetBooleani_v(GLenum target, GLuint index, GLboolean* data) {
GetBooleani_v_State(target, index, data);
}
void Disablei(GLenum target, GLuint index) {
Disablei_State(target, index);
}
@@ -15,6 +15,7 @@ namespace MobileGL::MG_Impl::GLImpl {
void BlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeAlpha);
void BlendFunci(GLuint buf, GLenum src, GLenum dst);
void BlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
void GetBooleani_v(GLenum target, GLuint index, GLboolean* data);
void Disablei(GLenum target, GLuint index);
void Enablei(GLenum target, GLuint index);
void BlendFunc(GLenum sfactor, GLenum dfactor);
@@ -13,7 +13,31 @@
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
namespace MobileGL::MG_Impl::GLImpl {
namespace {
Bool ValidateSamplerParameterValue(GLenum pname, const void* param, Bool isFloat, Bool isInteger) {
if (param == nullptr) return false;
switch (pname) {
case GL_TEXTURE_MIN_LOD:
case GL_TEXTURE_MAX_LOD:
case GL_TEXTURE_LOD_BIAS:
return true;
default:
break;
}
if (isFloat) {
return SamplerImpl::ValidateSamplerFloatParam(pname, *(const GLfloat*)param);
}
if (isInteger) {
return SamplerImpl::ValidateSamplerIntParam(pname, static_cast<GLint>(*(const GLuint*)param));
}
return SamplerImpl::ValidateSamplerIntParam(pname, *(const GLint*)param);
}
} // namespace
void SetSamplerParam_State(GLuint sampler, GLenum pname, const void* param, bool isFloat, bool isInteger) {
if (param == nullptr) return;
if (!SamplerImpl::ValidateSamplerName(sampler)) return;
Bool doesSamplerObjectCreated = MG_State::pGLContext->ValidateSamplerObject(sampler);
@@ -23,6 +47,7 @@ namespace MobileGL::MG_Impl::GLImpl {
}
auto& samplerObj = MG_State::pGLContext->GetSamplerObject(sampler);
if (!SamplerImpl::ValidateSamplerObject(sampler)) return;
if (!ValidateSamplerParameterValue(pname, param, isFloat, isInteger)) return;
using namespace MG_Util;
switch (pname) {
@@ -65,6 +90,7 @@ namespace MobileGL::MG_Impl::GLImpl {
}
void GetSamplerParam_State(GLuint sampler, GLenum pname, void* params, bool isFloat, bool isInteger) {
if (params == nullptr) return;
if (!SamplerImpl::ValidateSamplerName(sampler)) return;
Bool doesSamplerObjectCreated = MG_State::pGLContext->ValidateSamplerObject(sampler);
+213 -9
View File
@@ -9,35 +9,239 @@
#include "GL_Sync.h"
#include "MG_State/GLState/Core.h"
#include <MG_Backend/BackendObjects.h>
#include <MG_Backend/DirectGLES/BackendObject_DirectGLES.h>
#include <MG_Util/BackendLoaders/OpenGL/Loader.h>
#include <MG_State/GLState/ErrorState/Error.h>
namespace MobileGL::MG_Impl::GLImpl {
namespace {
const MG_External::GLESFunctionsTable* TryGetDirectGLESFunctions(const char* funcName) {
auto* activeBackend = MG_Backend::pActiveBackendObject.get();
if (!activeBackend) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", funcName, "No active backend object."));
return nullptr;
}
auto* directGLESBackend =
dynamic_cast<MG_Backend::DirectGLES::BackendObject_DirectGLES*>(activeBackend);
if (!directGLESBackend) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", funcName,
"Sync objects are only implemented for the DirectGLES backend."));
return nullptr;
}
return &directGLESBackend->GetGLESFunctions();
}
Bool ValidateFenceSyncArgs(const char* funcName, GLenum condition, GLbitfield flags) {
if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", funcName,
"condition must be GL_SYNC_GPU_COMMANDS_COMPLETE."));
return false;
}
if (flags != 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", funcName, "flags must be zero."));
return false;
}
return true;
}
Bool ValidateSyncHandle(const char* funcName, GLsync sync) {
if (sync != nullptr) {
return true;
}
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", funcName, "sync must be a valid non-null handle."));
return false;
}
}
GLsync FenceSync_Backend(GLenum condition, GLbitfield flags) {
return 0;
const auto* glesFuncs = TryGetDirectGLESFunctions(__func__);
if (!glesFuncs || !glesFuncs->glFenceSync) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not expose glFenceSync."));
return nullptr;
}
return glesFuncs->glFenceSync(condition, flags);
}
GLboolean IsSync_Backend(GLsync sync) {
const auto* glesFuncs = TryGetDirectGLESFunctions(__func__);
if (!glesFuncs || !glesFuncs->glIsSync) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not expose glIsSync."));
return GL_FALSE;
}
return glesFuncs->glIsSync(sync);
}
GLenum ClientWaitSync_Backend(GLsync sync, GLbitfield flags, GLuint64 timeout) {
return 0;
const auto* glesFuncs = TryGetDirectGLESFunctions(__func__);
if (!glesFuncs || !glesFuncs->glClientWaitSync) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not expose glClientWaitSync."));
return GL_WAIT_FAILED;
}
return glesFuncs->glClientWaitSync(sync, flags, timeout);
}
void DeleteSync_Backend(GLsync sync) {}
void WaitSync_Backend(GLsync sync, GLbitfield flags, GLuint64 timeout) {
const auto* glesFuncs = TryGetDirectGLESFunctions(__func__);
if (!glesFuncs || !glesFuncs->glWaitSync) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not expose glWaitSync."));
return;
}
glesFuncs->glWaitSync(sync, flags, timeout);
}
void GetSynciv_Backend(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) {
const auto* glesFuncs = TryGetDirectGLESFunctions(__func__);
if (!glesFuncs || !glesFuncs->glGetSynciv) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not expose glGetSynciv."));
return;
}
glesFuncs->glGetSynciv(sync, pname, bufSize, length, values);
}
void DeleteSync_Backend(GLsync sync) {
const auto* glesFuncs = TryGetDirectGLESFunctions(__func__);
if (!glesFuncs || !glesFuncs->glDeleteSync) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not expose glDeleteSync."));
return;
}
glesFuncs->glDeleteSync(sync);
}
GLsync FenceSync_State(GLenum condition, GLbitfield flags) {
return 0;
if (!ValidateFenceSyncArgs(__func__, condition, flags)) {
return nullptr;
}
return FenceSync_Backend(condition, flags);
}
GLboolean IsSync_State(GLsync sync) {
if (sync == nullptr) return GL_FALSE;
return IsSync_Backend(sync);
}
GLenum ClientWaitSync_State(GLsync sync, GLbitfield flags, GLuint64 timeout) {
return 0;
(void)timeout;
if (!ValidateSyncHandle(__func__, sync)) {
return GL_WAIT_FAILED;
}
if ((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) != 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"flags contains unsupported bits."));
return GL_WAIT_FAILED;
}
return ClientWaitSync_Backend(sync, flags, timeout);
}
void DeleteSync_State(GLsync sync) {}
void WaitSync_State(GLsync sync, GLbitfield flags, GLuint64 timeout) {
if (!ValidateSyncHandle(__func__, sync)) {
return;
}
if (flags != 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "flags must be zero."));
return;
}
if (timeout != GL_TIMEOUT_IGNORED) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "timeout must be GL_TIMEOUT_IGNORED."));
return;
}
WaitSync_Backend(sync, flags, timeout);
}
void GetSynciv_State(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) {
if (!ValidateSyncHandle(__func__, sync)) {
return;
}
if (bufSize < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "bufSize must be non-negative."));
return;
}
if (bufSize > 0 && values == nullptr) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"values must not be null when bufSize is positive."));
return;
}
switch (pname) {
case GL_OBJECT_TYPE:
case GL_SYNC_CONDITION:
case GL_SYNC_STATUS:
case GL_SYNC_FLAGS:
break;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Unsupported sync pname."));
return;
}
GetSynciv_Backend(sync, pname, bufSize, length, values);
}
void DeleteSync_State(GLsync sync) {
if (sync == nullptr) return;
DeleteSync_Backend(sync);
}
GLsync FenceSync(GLenum condition, GLbitfield flags) {
return 0;
return FenceSync_State(condition, flags);
}
GLboolean IsSync(GLsync sync) {
return IsSync_State(sync);
}
GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
return 0;
return ClientWaitSync_State(sync, flags, timeout);
}
void DeleteSync(GLsync sync) {}
void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
WaitSync_State(sync, flags, timeout);
}
void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) {
GetSynciv_State(sync, pname, bufSize, length, values);
}
void DeleteSync(GLsync sync) {
DeleteSync_State(sync);
}
} // namespace MobileGL::MG_Impl::GLImpl
+3
View File
@@ -11,6 +11,9 @@
namespace MobileGL::MG_Impl::GLImpl {
GLsync FenceSync(GLenum condition, GLbitfield flags);
GLboolean IsSync(GLsync sync);
void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values);
void DeleteSync(GLsync sync);
} // namespace MobileGL::MG_Impl::GLImpl
+128 -36
View File
@@ -31,6 +31,21 @@ namespace MobileGL::MG_Impl::GLImpl {
static SharedPtr<MG_State::GLState::ITextureObject> nullTextureObject;
static UnorderedMap<Uint, Bool> g_autoGenerateMipmapByTextureId;
void GetTexParameteriv_State(GLenum target, GLenum pname, GLint* params);
namespace {
void SetTextureBorderColorFromFloats(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
const GLfloat* params) {
textureObject->SetBorderColor(FloatVec4(params[0], params[1], params[2], params[3]));
}
void SetTextureBorderColorFromInts(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
const GLint* params) {
textureObject->SetBorderColor(FloatVec4(static_cast<Float>(params[0]), static_cast<Float>(params[1]),
static_cast<Float>(params[2]), static_cast<Float>(params[3])));
}
} // namespace
const SharedPtr<MG_State::GLState::ITextureObject>& GetTextureObjectByTarget(
TextureUploadTarget textureUploadTarget, TextureTarget textureTarget) {
if (TextureImpl::IsProxyTextureTarget(textureUploadTarget)) {
@@ -360,7 +375,7 @@ namespace MobileGL::MG_Impl::GLImpl {
// ======================= Processing ================================
auto& textureObject = GetTextureObjectByTarget(textureUploadTarget, textureTarget);
if (!textureObject) return;
THROW_UNIMPL_EXCEPTION;
SetTextureBorderColorFromFloats(textureObject, params);
break;
}
case GL_TEXTURE_SWIZZLE_RGBA: {
@@ -401,8 +416,7 @@ namespace MobileGL::MG_Impl::GLImpl {
// ======================= Processing ================================
auto& textureObject = GetTextureObjectByTarget(textureUploadTarget, textureTarget);
if (!textureObject) return;
THROW_UNIMPL_EXCEPTION;
SetTextureBorderColorFromInts(textureObject, params);
break;
}
case GL_TEXTURE_SWIZZLE_RGBA: {
@@ -436,7 +450,11 @@ namespace MobileGL::MG_Impl::GLImpl {
void TexParameterIiv_State(GLenum target, GLenum pname, const GLint* params) {
switch (pname) {
case GL_TEXTURE_BORDER_COLOR: {
THROW_UNIMPL_EXCEPTION;
TextureUploadTarget textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
auto& textureObject = GetTextureObjectByTarget(textureUploadTarget, textureTarget);
if (!textureObject) return;
SetTextureBorderColorFromInts(textureObject, params);
break;
}
case GL_TEXTURE_SWIZZLE_RGBA: {
@@ -470,7 +488,12 @@ namespace MobileGL::MG_Impl::GLImpl {
void TexParameterIuiv_State(GLenum target, GLenum pname, const GLuint* params) {
switch (pname) {
case GL_TEXTURE_BORDER_COLOR: {
THROW_UNIMPL_EXCEPTION;
TextureUploadTarget textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
auto& textureObject = GetTextureObjectByTarget(textureUploadTarget, textureTarget);
if (!textureObject) return;
textureObject->SetBorderColor(FloatVec4(static_cast<Float>(params[0]), static_cast<Float>(params[1]),
static_cast<Float>(params[2]), static_cast<Float>(params[3])));
break;
}
case GL_TEXTURE_SWIZZLE_RGBA: {
@@ -806,13 +829,17 @@ namespace MobileGL::MG_Impl::GLImpl {
}
void GetTexParameterIuiv_State(GLenum target, GLenum pname, GLuint* params) {
// TODO: implement
THROW_UNIMPL_EXCEPTION;
if (params == nullptr) return;
GLint signedParams[4] = {0, 0, 0, 0};
GetTexParameteriv_State(target, pname, signedParams);
for (int i = 0; i < 4; ++i) {
params[i] = static_cast<GLuint>(signedParams[i]);
}
}
void GetTexParameterIiv_State(GLenum target, GLenum pname, GLint* params) {
// TODO: implement
THROW_UNIMPL_EXCEPTION;
GetTexParameteriv_State(target, pname, params);
}
void GetTexParameteriv_State(GLenum target, GLenum pname, GLint* params) {
@@ -855,9 +882,48 @@ namespace MobileGL::MG_Impl::GLImpl {
}
break;
case GL_TEXTURE_BASE_LEVEL:
if (params) {
*params = static_cast<GLint>(textureObject->GetLevelRange().x());
}
break;
case GL_TEXTURE_MAX_LEVEL:
if (params) {
*params = static_cast<GLint>(textureObject->GetLevelRange().y());
}
break;
case GL_TEXTURE_BORDER_COLOR:
break; // TODO
if (params) {
const auto& borderColor = textureObject->GetBorderColor();
params[0] = static_cast<GLint>(borderColor.x());
params[1] = static_cast<GLint>(borderColor.y());
params[2] = static_cast<GLint>(borderColor.z());
params[3] = static_cast<GLint>(borderColor.w());
}
break;
case GL_TEXTURE_SWIZZLE_R:
if (params) {
*params = static_cast<GLint>(
MG_Util::ConvertTextureSwizzleParamToGLEnum(textureObject->GetSwizzleParam(TextureSwizzleParam::Red)));
}
break;
case GL_TEXTURE_SWIZZLE_G:
if (params) {
*params = static_cast<GLint>(MG_Util::ConvertTextureSwizzleParamToGLEnum(
textureObject->GetSwizzleParam(TextureSwizzleParam::Green)));
}
break;
case GL_TEXTURE_SWIZZLE_B:
if (params) {
*params = static_cast<GLint>(
MG_Util::ConvertTextureSwizzleParamToGLEnum(textureObject->GetSwizzleParam(TextureSwizzleParam::Blue)));
}
break;
case GL_TEXTURE_SWIZZLE_A:
if (params) {
*params = static_cast<GLint>(MG_Util::ConvertTextureSwizzleParamToGLEnum(
textureObject->GetSwizzleParam(TextureSwizzleParam::Alpha)));
}
break;
case GL_TEXTURE_WRAP_S:
if (params) {
*params = (GLint)MG_Util::ConvertSamplerWrapModeToGLEnum(textureObject->GetSamplerObject()->GetWrapS());
@@ -933,14 +999,50 @@ namespace MobileGL::MG_Impl::GLImpl {
}
break;
case GL_TEXTURE_BASE_LEVEL:
if (params) {
*params = static_cast<GLfloat>(textureObject->GetLevelRange().x());
}
break;
case GL_TEXTURE_MAX_LEVEL:
if (params) {
*params = static_cast<GLfloat>(textureObject->GetLevelRange().y());
}
break;
case GL_TEXTURE_SWIZZLE_R:
if (params) {
*params = static_cast<GLfloat>(
MG_Util::ConvertTextureSwizzleParamToGLEnum(textureObject->GetSwizzleParam(TextureSwizzleParam::Red)));
}
break;
case GL_TEXTURE_SWIZZLE_G:
if (params) {
*params = static_cast<GLfloat>(MG_Util::ConvertTextureSwizzleParamToGLEnum(
textureObject->GetSwizzleParam(TextureSwizzleParam::Green)));
}
break;
case GL_TEXTURE_SWIZZLE_B:
if (params) {
*params = static_cast<GLfloat>(MG_Util::ConvertTextureSwizzleParamToGLEnum(
textureObject->GetSwizzleParam(TextureSwizzleParam::Blue)));
}
break;
case GL_TEXTURE_SWIZZLE_A:
if (params) {
*params = static_cast<GLfloat>(MG_Util::ConvertTextureSwizzleParamToGLEnum(
textureObject->GetSwizzleParam(TextureSwizzleParam::Alpha)));
}
break;
case GL_TEXTURE_SWIZZLE_RGBA:
case GL_TEXTURE_BORDER_COLOR:
break; // TODO
case GL_TEXTURE_BORDER_COLOR:
if (params) {
const auto& borderColor = textureObject->GetBorderColor();
params[0] = borderColor.x();
params[1] = borderColor.y();
params[2] = borderColor.z();
params[3] = borderColor.w();
}
break;
case GL_TEXTURE_WRAP_S:
if (params) {
*params =
@@ -1386,7 +1488,7 @@ namespace MobileGL::MG_Impl::GLImpl {
}
// Add to GL_Texture.cpp
void GetTexImage_State(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
Bool GetTexImage_State(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
// ======================= Converting ================================
TextureUploadTarget textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
@@ -1399,7 +1501,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State", "Invalid texture target"));
return;
return false;
}
// Validate level
@@ -1407,7 +1509,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State", "Level must be non-negative"));
return;
return false;
}
// Validate format
@@ -1415,7 +1517,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State", "Invalid format"));
return;
return false;
}
// Validate type
@@ -1423,7 +1525,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State", "Invalid pixel data type"));
return;
return false;
}
// Get texture object
@@ -1438,7 +1540,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->RecordError(ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"No valid texture bound to target"));
return;
return false;
}
// Check texture completeness
@@ -1446,7 +1548,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State", "Texture is incomplete"));
return;
return false;
}
// Check PBO state
@@ -1459,7 +1561,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"Pixel pack buffer is currently mapped"));
return;
return false;
}
// Check alignment
@@ -1469,7 +1571,7 @@ namespace MobileGL::MG_Impl::GLImpl {
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"Pixel data not aligned for pixel pack buffer"));
return;
return false;
}
}
@@ -1482,21 +1584,11 @@ namespace MobileGL::MG_Impl::GLImpl {
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"No stencil buffer for stencil index format"));
return;
return false;
}
}
// Check for multisampling
if (textureObject->GetStorageType() == TextureStorageType::Mipmap) {
auto mipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
if (mipmapObject->GetMipmapLevelCount() > 1) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetTexImage_State",
"Multisampled textures not supported for GetTexImage"));
return;
}
}
return true;
}
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
@@ -1538,9 +1630,6 @@ namespace MobileGL::MG_Impl::GLImpl {
textureObject = MG_State::pGLContext->GetTextureObject(texture);
}
MG_State::pGLContext->GetImageTextureBinding(static_cast<Int>(unit))
.Bind(textureObject, level, layered, layer, access, format);
auto bindImageTexture = MG_Backend::gBackendFunctionsTable.GL.BindImageTexture;
if (!bindImageTexture) {
MG_State::pGLContext->RecordError(
@@ -1549,6 +1638,9 @@ namespace MobileGL::MG_Impl::GLImpl {
"Backend does not support image texture binding."));
return;
}
MG_State::pGLContext->GetImageTextureBinding(static_cast<Int>(unit))
.Bind(textureObject, level, layered, layer, access, format);
bindImageTexture(unit, texture, level, layered, layer, access, format);
}
@@ -1557,7 +1649,7 @@ namespace MobileGL::MG_Impl::GLImpl {
}
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
GetTexImage_State(target, level, format, type, pixels);
if (!GetTexImage_State(target, level, format, type, pixels)) return;
GetTexImage_Backend(target, level, format, type, pixels);
}
@@ -7,7 +7,11 @@
// End of Source File Header
#include "ProxyTexture.h"
#include <MG_State/GLState/TextureState/TextureObject1D.h>
#include <MG_State/GLState/TextureState/TextureObject2D.h>
#include <MG_State/GLState/TextureState/TextureObject2DCube.h>
#include <MG_State/GLState/TextureState/TextureObject3D.h>
#include <MG_State/GLState/TextureState/TextureObjectStubs.h>
namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
UniquePtr<ProxyTextureManager> pProxyTextureManager;
@@ -37,7 +41,39 @@ namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
m_proxyTexturesMap.erase(it);
}
auto& obj = m_proxyTexturesMap[target];
obj = MakeShared<MG_State::GLState::TextureObject2D>(0);
switch (target) {
case TextureUploadTarget::ProxyTexture1D:
case TextureUploadTarget::ProxyTexture1DArray:
obj = MakeShared<MG_State::GLState::TextureObject1D>(0);
break;
case TextureUploadTarget::ProxyTexture2D:
obj = MakeShared<MG_State::GLState::TextureObject2D>(0);
break;
case TextureUploadTarget::ProxyTexture3D:
obj = MakeShared<MG_State::GLState::TextureObject3D>(0);
break;
case TextureUploadTarget::ProxyCubeMap:
obj = MakeShared<MG_State::GLState::TextureObject2DCube>(0);
break;
case TextureUploadTarget::ProxyTextureRectangle:
obj = MakeShared<MG_State::GLState::TextureObjectRectangle>(0);
break;
case TextureUploadTarget::ProxyTexture2DArray:
obj = MakeShared<MG_State::GLState::TextureObject2DArray>(0);
break;
case TextureUploadTarget::ProxyCubeMapArray:
obj = MakeShared<MG_State::GLState::TextureObjectCubeMapArray>(0);
break;
case TextureUploadTarget::ProxyTexture2DMultisample:
obj = MakeShared<MG_State::GLState::TextureObject2DMultisample>(0);
break;
case TextureUploadTarget::ProxyTexture2DMultisampleArray:
obj = MakeShared<MG_State::GLState::TextureObject2DMultisampleArray>(0);
break;
default:
obj = MakeShared<MG_State::GLState::TextureObject2D>(0);
break;
}
return obj;
}
@@ -11,8 +11,64 @@
#include <MG_State/GLState/Core.h>
#include <MG_State/GLState/ErrorState/Error.h>
#include <MG_Util/Converters/GLToMG/DataTypeConverter.h>
#include <MG_Util/Converters/MGToGL/DataTypeConverter.h>
namespace MobileGL::MG_Impl::GLImpl {
namespace {
static bool ValidateCurrentVertexAttribIndex(GLuint index, const char* funcName) {
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return false;
if (index == 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", funcName,
"Generic vertex attribute 0 current value cannot be modified."));
return false;
}
return true;
}
static bool TryGetVertexAttribute(GLuint index, const MG_State::GLState::VertexAttribute** outAttr) {
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return false;
auto& vao = MG_State::pGLContext->GetBoundVertexArray();
if (!vao) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "No vertex array object is bound."));
return false;
}
*outAttr = &vao->GetAttribute(index);
return true;
}
static bool IsCurrentVertexAttribQuery(GLenum pname) {
return pname == GL_CURRENT_VERTEX_ATTRIB;
}
static bool ValidateVertexAttribPname(GLenum pname) {
switch (pname) {
case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
case GL_VERTEX_ATTRIB_ARRAY_SIZE:
case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
case GL_VERTEX_ATTRIB_ARRAY_TYPE:
case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
case GL_CURRENT_VERTEX_ATTRIB:
case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
case GL_VERTEX_ATTRIB_ARRAY_POINTER:
return true;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Unsupported vertex attrib pname: " + std::to_string(pname)));
return false;
}
}
} // namespace
void DisableVertexAttribArray_State(GLuint index) {
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
@@ -163,6 +219,287 @@ namespace MobileGL::MG_Impl::GLImpl {
}
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
void VertexAttrib1f(GLuint index, GLfloat x) {
if (!ValidateCurrentVertexAttribIndex(index, __func__)) return;
MG_State::pGLContext->SetCurrentVertexAttributeFloat(index, {x, 0.0f, 0.0f, 1.0f});
}
void VertexAttrib1fv(GLuint index, const GLfloat* v) {
if (!v) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "value pointer cannot be null."));
return;
}
VertexAttrib1f(index, v[0]);
}
void VertexAttrib2f(GLuint index, GLfloat x, GLfloat y) {
if (!ValidateCurrentVertexAttribIndex(index, __func__)) return;
MG_State::pGLContext->SetCurrentVertexAttributeFloat(index, {x, y, 0.0f, 1.0f});
}
void VertexAttrib2fv(GLuint index, const GLfloat* v) {
if (!v) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "value pointer cannot be null."));
return;
}
VertexAttrib2f(index, v[0], v[1]);
}
void VertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) {
if (!ValidateCurrentVertexAttribIndex(index, __func__)) return;
MG_State::pGLContext->SetCurrentVertexAttributeFloat(index, {x, y, z, 1.0f});
}
void VertexAttrib3fv(GLuint index, const GLfloat* v) {
if (!v) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "value pointer cannot be null."));
return;
}
VertexAttrib3f(index, v[0], v[1], v[2]);
}
void VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
if (!ValidateCurrentVertexAttribIndex(index, __func__)) return;
MG_State::pGLContext->SetCurrentVertexAttributeFloat(index, {x, y, z, w});
}
void VertexAttrib4fv(GLuint index, const GLfloat* v) {
if (!v) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "value pointer cannot be null."));
return;
}
VertexAttrib4f(index, v[0], v[1], v[2], v[3]);
}
void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w) {
if (!ValidateCurrentVertexAttribIndex(index, __func__)) return;
MG_State::pGLContext->SetCurrentVertexAttributeInt(index, {x, y, z, w});
}
void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) {
if (!ValidateCurrentVertexAttribIndex(index, __func__)) return;
MG_State::pGLContext->SetCurrentVertexAttributeUint(index, {x, y, z, w});
}
void VertexAttribI4iv(GLuint index, const GLint* v) {
if (!v) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "value pointer cannot be null."));
return;
}
VertexAttribI4i(index, v[0], v[1], v[2], v[3]);
}
void VertexAttribI4uiv(GLuint index, const GLuint* v) {
if (!v) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "value pointer cannot be null."));
return;
}
VertexAttribI4ui(index, v[0], v[1], v[2], v[3]);
}
void VertexAttrib4Nub(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w) {
constexpr float kInv255 = 1.0f / 255.0f;
VertexAttrib4f(index, x * kInv255, y * kInv255, z * kInv255, w * kInv255);
}
void VertexAttrib4Nubv(GLuint index, const GLubyte* v) {
if (!v) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "value pointer cannot be null."));
return;
}
VertexAttrib4Nub(index, v[0], v[1], v[2], v[3]);
}
void VertexAttrib4ubv(GLuint index, const GLubyte* v) {
if (!v) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "value pointer cannot be null."));
return;
}
VertexAttrib4f(index, static_cast<GLfloat>(v[0]), static_cast<GLfloat>(v[1]), static_cast<GLfloat>(v[2]),
static_cast<GLfloat>(v[3]));
}
void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) {
if (!params) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "params pointer cannot be null."));
return;
}
if (!ValidateVertexAttribPname(pname)) return;
if (IsCurrentVertexAttribQuery(pname)) {
const auto& current = MG_State::pGLContext->GetCurrentVertexAttribute(index);
params[0] = current.floatValue[0];
params[1] = current.floatValue[1];
params[2] = current.floatValue[2];
params[3] = current.floatValue[3];
return;
}
const MG_State::GLState::VertexAttribute* attr = nullptr;
if (!TryGetVertexAttribute(index, &attr)) return;
switch (pname) {
case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
params[0] = attr->Enabled ? 1.0f : 0.0f;
return;
case GL_VERTEX_ATTRIB_ARRAY_SIZE:
params[0] = static_cast<GLfloat>(attr->Size);
return;
case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
params[0] = static_cast<GLfloat>(attr->Stride);
return;
case GL_VERTEX_ATTRIB_ARRAY_TYPE:
params[0] = static_cast<GLfloat>(MG_Util::ConvertDataTypeToGLEnum(attr->Type));
return;
case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
params[0] = attr->Normalized ? 1.0f : 0.0f;
return;
case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
params[0] = attr->Buffer ? static_cast<GLfloat>(attr->Buffer->GetExternalIndex()) : 0.0f;
return;
case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
params[0] = attr->IsInteger ? 1.0f : 0.0f;
return;
case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
params[0] = static_cast<GLfloat>(attr->Divisor);
return;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Unsupported float vertex attrib pname: " + std::to_string(pname)));
return;
}
}
void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params) {
if (!params) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "params pointer cannot be null."));
return;
}
if (!ValidateVertexAttribPname(pname)) return;
if (IsCurrentVertexAttribQuery(pname)) {
const auto& current = MG_State::pGLContext->GetCurrentVertexAttribute(index);
params[0] = current.intValue[0];
params[1] = current.intValue[1];
params[2] = current.intValue[2];
params[3] = current.intValue[3];
return;
}
const MG_State::GLState::VertexAttribute* attr = nullptr;
if (!TryGetVertexAttribute(index, &attr)) return;
switch (pname) {
case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
params[0] = attr->Enabled ? GL_TRUE : GL_FALSE;
return;
case GL_VERTEX_ATTRIB_ARRAY_SIZE:
params[0] = attr->Size;
return;
case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
params[0] = attr->Stride;
return;
case GL_VERTEX_ATTRIB_ARRAY_TYPE:
params[0] = static_cast<GLint>(MG_Util::ConvertDataTypeToGLEnum(attr->Type));
return;
case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
params[0] = attr->Normalized ? GL_TRUE : GL_FALSE;
return;
case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
params[0] = attr->Buffer ? static_cast<GLint>(attr->Buffer->GetExternalIndex()) : 0;
return;
case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
params[0] = attr->IsInteger ? GL_TRUE : GL_FALSE;
return;
case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
params[0] = static_cast<GLint>(attr->Divisor);
return;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Unsupported integer vertex attrib pname: " + std::to_string(pname)));
return;
}
}
void GetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer) {
if (!pointer) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "pointer cannot be null."));
return;
}
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"pname must be GL_VERTEX_ATTRIB_ARRAY_POINTER."));
return;
}
auto& vao = MG_State::pGLContext->GetBoundVertexArray();
if (!vao) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "No vertex array object is bound."));
return;
}
const auto& attr = vao->GetAttribute(index);
*pointer = reinterpret_cast<void*>(attr.Offset);
}
void GetVertexAttribIiv(GLuint index, GLenum pname, GLint* params) {
GetVertexAttribiv(index, pname, params);
}
void GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params) {
if (!params) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "params pointer cannot be null."));
return;
}
if (!ValidateVertexAttribPname(pname)) return;
if (IsCurrentVertexAttribQuery(pname)) {
const auto& current = MG_State::pGLContext->GetCurrentVertexAttribute(index);
params[0] = current.uintValue[0];
params[1] = current.uintValue[1];
params[2] = current.uintValue[2];
params[3] = current.uintValue[3];
return;
}
GLint signedParams[4] = {};
GetVertexAttribiv(index, pname, signedParams);
params[0] = static_cast<GLuint>(signedParams[0]);
}
void VertexAttribDivisor(GLuint index, GLuint divisor) {
VertexAttribDivisor_State(index, divisor);
}
@@ -11,6 +11,26 @@
namespace MobileGL::MG_Impl::GLImpl {
/* @INSERTION_POINT:FUNCTION_DECLARATION@ */
void VertexAttrib1f(GLuint index, GLfloat x);
void VertexAttrib1fv(GLuint index, const GLfloat* v);
void VertexAttrib2f(GLuint index, GLfloat x, GLfloat y);
void VertexAttrib2fv(GLuint index, const GLfloat* v);
void VertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z);
void VertexAttrib3fv(GLuint index, const GLfloat* v);
void VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
void VertexAttrib4fv(GLuint index, const GLfloat* v);
void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w);
void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
void VertexAttribI4iv(GLuint index, const GLint* v);
void VertexAttribI4uiv(GLuint index, const GLuint* v);
void VertexAttrib4Nub(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
void VertexAttrib4Nubv(GLuint index, const GLubyte* v);
void VertexAttrib4ubv(GLuint index, const GLubyte* v);
void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params);
void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params);
void GetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer);
void GetVertexAttribIiv(GLuint index, GLenum pname, GLint* params);
void GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params);
void VertexAttribDivisor(GLuint index, GLuint divisor);
GLboolean IsVertexArray(GLuint array);
void DisableVertexAttribArray(GLuint index);
+1
View File
@@ -35,6 +35,7 @@ namespace MobileGL::MG_Impl {
stencilTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, {{512, 512, 1}, 0});
// stencilTex->SetMipmapLevel({{512, 512, 1}, 0, false, 0, {nullptr, 0}});
fbo0->AttachTexture(FramebufferAttachmentType::Color0, colorTex);
fbo0->AttachTexture(FramebufferAttachmentType::BackLeft, colorTex);
fbo0->AttachTexture(FramebufferAttachmentType::Depth, depthTex);
fbo0->AttachTexture(FramebufferAttachmentType::Stencil, stencilTex);
GLImpl::FramebufferImpl::pDefaultFramebufferInfo =
+15
View File
@@ -1139,6 +1139,21 @@ namespace MobileGL {
return EGL_NO_SURFACE;
}
Bool EGLContext::IsDoubleBufferedSurface(EGLSurfaceHandle surface) const {
const std::lock_guard<std::recursive_mutex> lock(m_mutex);
const auto* surfaceObject = TryGetSurface(surface);
if (!surfaceObject) {
return false;
}
if (surfaceObject->RenderBuffer != EGL_BACK_BUFFER) {
return false;
}
return surfaceObject->Type == SurfaceType::Window ||
surfaceObject->Type == SurfaceType::PlatformWindow;
}
EGLContext::EGLSyncHandle EGLContext::CreateSync(EGLDisplayHandle display, EGLenum type,
const EGLAttrib* attribList) {
const std::lock_guard<std::recursive_mutex> lock(m_mutex);
+1
View File
@@ -87,6 +87,7 @@ namespace MobileGL {
EGLContextHandle GetCurrentContext() const;
EGLDisplayHandle GetCurrentDisplay() const;
EGLSurfaceHandle GetCurrentSurface(EGLint readdraw) const;
Bool IsDoubleBufferedSurface(EGLSurfaceHandle surface) const;
// Sync
EGLSyncHandle CreateSync(EGLDisplayHandle display, EGLenum type, const EGLAttrib* attribList);
@@ -120,10 +120,13 @@ namespace MobileGL::MG_State::GLState {
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 (write) {
m_change.Bits |= BufferChangeBits::ForbidInvalidationBit;
m_change.Bits |= BufferChangeBits::ForbidUnsynchronizationBit;
}
if (m_mappingAccess & BufferMappingAccessBit::Write) {
m_stagingData.resize(m_size);
@@ -148,6 +151,13 @@ namespace MobileGL::MG_State::GLState {
m_isMapped = true;
m_mappingAccess = access;
m_mappedRange = range;
m_change.Bits |=
!(access & BufferMappingAccessBit::InvalidateBuffer || access & BufferMappingAccessBit::InvalidateRange)
? BufferChangeBits::ForbidInvalidationBit
: BufferChangeBits::None;
m_change.Bits |= !(access & BufferMappingAccessBit::Unsynchronized)
? BufferChangeBits::ForbidUnsynchronizationBit
: BufferChangeBits::None;
if (access & BufferMappingAccessBit::Write) {
m_stagingData.resize(range.end - range.start);
@@ -162,14 +172,6 @@ namespace MobileGL::MG_State::GLState {
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 {
@@ -209,6 +211,18 @@ namespace MobileGL::MG_State::GLState {
return m_isMapped ? m_mappedRange : Range1D{0, 0};
}
void* BufferObject::GetMappedPointer() {
if (!m_isMapped) {
return nullptr;
}
if (m_ownsStagingData) {
return m_stagingData.data();
}
return m_dataPtr->data() + m_mappedRange.start;
}
Flags<BufferMappingAccessBit> BufferObject::GetMappingAccess() const {
return m_isMapped ? m_mappingAccess : BufferMappingAccessBit::Null;
}
@@ -94,6 +94,7 @@ namespace MobileGL {
SizeT GetSize() const;
BufferUsage GetUsage() const;
Range1D GetMappedRange() const;
void* GetMappedPointer();
const SharedPtr<Data>& GetDataReadOnly() const;
Flags<BufferMappingAccessBit> GetMappingAccess() const;
Uint GetExternalIndex() const;
@@ -56,6 +56,14 @@ namespace MobileGL::MG_State::GLState {
bindingSlot.Bind(nullptr);
}
}
for (auto& bindingPointArray : m_bufferBindPointTargets) {
for (auto& bindingPoint : bindingPointArray) {
if (bindingPoint.GetBoundObject() == it->second) {
bindingPoint.Bind(nullptr);
bindingPoint.ClearRange();
}
}
}
m_bufferObjects.erase(it);
}
m_indexGenerator.Delete(index);
+92 -3
View File
@@ -285,6 +285,34 @@ namespace MobileGL::MG_State {
return m_renderState.GetViewport();
}
void GLContext::SetLineWidth(Float width) {
m_renderState.SetLineWidth(width);
}
Float GLContext::GetLineWidth() const {
return m_renderState.GetLineWidth();
}
void GLContext::SetPointSize(Float size) {
m_renderState.SetPointSize(size);
}
Float GLContext::GetPointSize() const {
return m_renderState.GetPointSize();
}
void GLContext::SetPolygonOffset(Float factor, Float units) {
m_renderState.SetPolygonOffset(factor, units);
}
Float GLContext::GetPolygonOffsetFactor() const {
return m_renderState.GetPolygonOffsetFactor();
}
Float GLContext::GetPolygonOffsetUnits() const {
return m_renderState.GetPolygonOffsetUnits();
}
void GLContext::SetCapability(CapabilityInput cap, Bool enabled) {
m_renderState.SetCapability(cap, enabled);
}
@@ -337,6 +365,14 @@ namespace MobileGL::MG_State {
m_renderState.GetBlendEquationIndexed(index, color, alpha);
}
void GLContext::SetLogicOp(LogicOperation logicOp) {
m_renderState.SetLogicOp(logicOp);
}
LogicOperation GLContext::GetLogicOp() const {
return m_renderState.GetLogicOp();
}
void GLContext::SetDepthFunc(DepthTestFunc func) {
m_renderState.SetDepthFunc(func);
}
@@ -353,6 +389,23 @@ namespace MobileGL::MG_State {
return m_renderState.GetDepthMask();
}
void GLContext::SetStencilFunc(StencilFace face, DepthTestFunc func, Int ref, Uint32 mask) {
m_renderState.SetStencilFunc(face, func, ref, mask);
}
void GLContext::SetStencilMask(StencilFace face, Uint32 mask) {
m_renderState.SetStencilMask(face, mask);
}
void GLContext::SetStencilOp(StencilFace face, StencilOperation fail, StencilOperation depthFail,
StencilOperation depthPass) {
m_renderState.SetStencilOp(face, fail, depthFail, depthPass);
}
const StencilFaceState& GLContext::GetStencilState(StencilFace face) const {
return m_renderState.GetStencilState(face);
}
void GLContext::SetColorMask(BoolVec4 mask) {
m_renderState.SetColorMask(mask);
}
@@ -381,9 +434,45 @@ namespace MobileGL::MG_State {
m_renderState.SetClearStencil(stencil);
}
Uint32 GLContext::GetClearStencil() const {
return m_renderState.GetClearStencil();
}
Uint32 GLContext::GetClearStencil() const {
return m_renderState.GetClearStencil();
}
void GLContext::SetBlendColor(FloatVec4 color) {
m_renderState.SetBlendColor(color);
}
const FloatVec4& GLContext::GetBlendColor() const {
return m_renderState.GetBlendColor();
}
void GLContext::SetDepthRange(FloatVec2 range) {
m_renderState.SetDepthRange(range);
}
const FloatVec2& GLContext::GetDepthRange() const {
return m_renderState.GetDepthRange();
}
void GLContext::SetSampleCoverage(Float value, Bool invert) {
m_renderState.SetSampleCoverage(value, invert);
}
Float GLContext::GetSampleCoverageValue() const {
return m_renderState.GetSampleCoverageValue();
}
Bool GLContext::GetSampleCoverageInvert() const {
return m_renderState.GetSampleCoverageInvert();
}
void GLContext::SetSampleMaskValue(Uint32 mask) {
m_renderState.SetSampleMaskValue(mask);
}
Uint32 GLContext::GetSampleMaskValue() const {
return m_renderState.GetSampleMaskValue();
}
void GLContext::SetPixelStoreParam(PixelStoreParam param, Int value) {
m_renderState.SetPixelStoreParam(param, value);
+23
View File
@@ -102,6 +102,13 @@ namespace MobileGL {
const RenderStateParameters& GetRenderStateParameters() const;
void SetViewport(IntVec4 viewport); // x, y, width, height
const IntVec4& GetViewport() const; // x, y, width, height
void SetLineWidth(Float width);
Float GetLineWidth() const;
void SetPointSize(Float size);
Float GetPointSize() const;
void SetPolygonOffset(Float factor, Float units);
Float GetPolygonOffsetFactor() const;
Float GetPolygonOffsetUnits() const;
void SetCapability(CapabilityInput cap, Bool enabled);
Bool IsCapabilityEnabled(CapabilityInput cap) const;
void SetCapabilityIndexed(CapabilityInput cap, Uint index, Bool enabled);
@@ -117,10 +124,17 @@ namespace MobileGL {
void GetBlendEquation(BlendEquation& color, BlendEquation& alpha) const;
void SetBlendEquationIndexed(Uint index, BlendEquation color, BlendEquation alpha);
void GetBlendEquationIndexed(Uint index, BlendEquation& color, BlendEquation& alpha) const;
void SetLogicOp(LogicOperation logicOp);
LogicOperation GetLogicOp() const;
void SetDepthFunc(DepthTestFunc func);
DepthTestFunc GetDepthFunc() const;
void SetDepthMask(Bool flag);
Bool GetDepthMask() const;
void SetStencilFunc(StencilFace face, DepthTestFunc func, Int ref, Uint32 mask);
void SetStencilMask(StencilFace face, Uint32 mask);
void SetStencilOp(StencilFace face, StencilOperation fail, StencilOperation depthFail,
StencilOperation depthPass);
const StencilFaceState& GetStencilState(StencilFace face) const;
void SetColorMask(BoolVec4 mask);
BoolVec4 GetColorMask() const;
void SetClearColor(FloatVec4 color);
@@ -129,6 +143,15 @@ namespace MobileGL {
Float GetClearDepth() const;
void SetClearStencil(Int stencil);
Uint32 GetClearStencil() const;
void SetBlendColor(FloatVec4 color);
const FloatVec4& GetBlendColor() const;
void SetDepthRange(FloatVec2 range);
const FloatVec2& GetDepthRange() const;
void SetSampleCoverage(Float value, Bool invert);
Float GetSampleCoverageValue() const;
Bool GetSampleCoverageInvert() const;
void SetSampleMaskValue(Uint32 mask);
Uint32 GetSampleMaskValue() const;
void SetPixelStoreParam(PixelStoreParam param, Int value);
Int GetPixelStoreParam(PixelStoreParam param) const;
PixelStoreParameters GetPixelStoreParameters(Bool isUnpack) const;
@@ -12,8 +12,8 @@
namespace MobileGL::MG_State::GLState {
// FramebufferAttachmentObject
FramebufferAttachmentObject::FramebufferAttachmentObject(
const SharedPtr<MG_State::GLState::ITextureObject>& texture, Int level)
: m_texture(texture), m_textureLevel(level) {}
const SharedPtr<MG_State::GLState::ITextureObject>& texture, TextureUploadTarget textureUploadTarget, Int level)
: m_texture(texture), m_textureUploadTarget(textureUploadTarget), m_textureLevel(level) {}
FramebufferAttachmentObject::FramebufferAttachmentObject(const SharedPtr<RenderbufferObject>& renderbuffer)
: m_renderbuffer(renderbuffer) {}
FramebufferAttachmentObject::FramebufferAttachmentObject(Bool IsValid)
@@ -45,6 +45,10 @@ namespace MobileGL::MG_State::GLState {
return m_textureLevel;
}
TextureUploadTarget FramebufferAttachmentObject::GetTextureUploadTarget() const {
return m_textureUploadTarget;
}
Bool FramebufferAttachmentObject::IsComplete() const {
if (IsTexture()) {
Bool complete = m_texture->IsComplete();
@@ -59,11 +63,18 @@ namespace MobileGL::MG_State::GLState {
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);
TextureUploadTarget resolvedTarget = m_textureUploadTarget;
if (resolvedTarget == TextureUploadTarget::Unknown) {
const auto& uploadTargets = m_texture->GetUploadTargets();
MOBILEGL_ASSERT(!uploadTargets.empty(),
"FramebufferAttachmentObject::GetSize: textureId=%u exposes no upload targets",
m_texture->GetExternalIndex());
resolvedTarget = uploadTargets[0];
}
return textureMipmapObject->GetMipmapTexelSize(resolvedTarget, m_textureLevel);
} else if (IsRenderbuffer()) {
return {m_renderbuffer->GetWidth(), m_renderbuffer->GetHeight(), 1};
}
@@ -79,13 +90,16 @@ namespace MobileGL::MG_State::GLState {
: m_externalIndex(externalIndex), m_attachmentVersions{}, m_drawBuffers{} {
m_attachmentObjects.fill(FramebufferAttachmentObject(false));
m_drawBuffers.fill(FramebufferAttachmentType::None);
m_drawBuffers[0] = FramebufferAttachmentType::Color0;
const FramebufferAttachmentType defaultColorBuffer =
(externalIndex == 0) ? FramebufferAttachmentType::BackLeft : FramebufferAttachmentType::Color0;
m_drawBuffers[0] = defaultColorBuffer;
m_readBuffer = defaultColorBuffer;
m_attachmentVersions.fill(0);
}
void FramebufferObject::AttachTexture(FramebufferAttachmentType type, const SharedPtr<ITextureObject>& texture,
int level) {
m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(texture, level);
TextureUploadTarget textureUploadTarget, int level) {
m_attachmentObjects[static_cast<SizeT>(type)] = FramebufferAttachmentObject(texture, textureUploadTarget, level);
BumpAttachmentVersion(type);
}
@@ -150,6 +164,12 @@ namespace MobileGL::MG_State::GLState {
return m_drawBuffers;
}
void FramebufferObject::SetReadBuffer(FramebufferAttachmentType buf) {
if (m_readBuffer == buf) return;
m_readBuffer = buf;
++m_objectVersion;
}
Uint FramebufferObject::GetExternalIndex() const {
return m_externalIndex;
}
@@ -73,6 +73,7 @@ namespace MobileGL {
class FramebufferAttachmentObject {
public:
explicit FramebufferAttachmentObject(const SharedPtr<MG_State::GLState::ITextureObject>& texture,
TextureUploadTarget textureUploadTarget,
Int level = 0);
explicit FramebufferAttachmentObject(const SharedPtr<RenderbufferObject>& renderbuffer);
explicit FramebufferAttachmentObject(Bool IsValid = true);
@@ -83,6 +84,7 @@ namespace MobileGL {
const SharedPtr<MG_State::GLState::ITextureObject>& GetTexture() const;
const SharedPtr<RenderbufferObject>& GetRenderbuffer() const;
Int GetTextureLevel() const;
TextureUploadTarget GetTextureUploadTarget() const;
Bool IsComplete() const;
IntVec3 GetSize() const;
Bool IsValid() const;
@@ -90,6 +92,7 @@ namespace MobileGL {
private:
SharedPtr<MG_State::GLState::ITextureObject> m_texture = nullptr;
SharedPtr<RenderbufferObject> m_renderbuffer = nullptr;
TextureUploadTarget m_textureUploadTarget = TextureUploadTarget::Unknown;
Int m_textureLevel = 0;
Bool m_isValid = true;
};
@@ -108,7 +111,8 @@ namespace MobileGL {
FramebufferObject(Uint externalIndex);
void AttachTexture(FramebufferAttachmentType type, const SharedPtr<ITextureObject>& texture, int level = 0);
void AttachTexture(FramebufferAttachmentType type, const SharedPtr<ITextureObject>& texture,
TextureUploadTarget textureUploadTarget = TextureUploadTarget::Unknown, int level = 0);
void AttachRenderbuffer(FramebufferAttachmentType type, const SharedPtr<RenderbufferObject>& renderbuffer);
void Detach(FramebufferAttachmentType type);
const FramebufferAttachmentObject& GetAttachment(FramebufferAttachmentType type) const;
@@ -117,7 +121,7 @@ namespace MobileGL {
// aka. `buffer` as in glDrawBuffers/glReadBuffers
void SetDrawBuffer(Uint index, FramebufferAttachmentType buffer);
const FramebufferAttachmentArray& GetDrawBuffers() const;
void SetReadBuffer(FramebufferAttachmentType buf) { m_readBuffer = buf; }
void SetReadBuffer(FramebufferAttachmentType buf);
FramebufferAttachmentType GetReadBuffer() const { return m_readBuffer; }
FramebufferAttachmentVersionArray GetAllFramebufferAttachmentVersions() const {
@@ -136,7 +140,7 @@ namespace MobileGL {
FramebufferAttachmentVersionArray m_attachmentVersions;
FramebufferAttachmentArray m_drawBuffers; // Probably no versioning needed for this, just check equality
FramebufferAttachmentType m_readBuffer = FramebufferAttachmentType::Color0; // ditto
FramebufferAttachmentType m_readBuffer = FramebufferAttachmentType::None;
// This version will bump when draw/read buffer changes (by `glDrawBuffer(s)`/`glReadBuffer`)
Uint16 m_objectVersion = 0;
@@ -62,7 +62,7 @@ namespace MobileGL::MG_State::GLState {
if (it != m_framebufferObjects.end()) {
for (auto& bindingSlot : m_bindingSlots) {
if (bindingSlot.GetBoundObject() == it->second) {
bindingSlot.Bind(nullptr);
bindingSlot.Bind(GetFramebufferObject(0));
}
}
m_framebufferObjects.erase(it);
@@ -60,6 +60,27 @@ namespace {
}
namespace MobileGL::MG_State::GLState {
void ProgramObject::ResetLinkArtifacts() {
m_program.reset();
m_generatedSpirv.clear();
m_uniformLocations.clear();
m_uniformIndexInTProgram.clear();
m_uniformSamplerOrImageUnitIndex.clear();
m_uniformBlockIndexByName.clear();
m_uniformBlockBinding.clear();
m_uniformOffsets.clear();
m_uniformSizesInBytes.clear();
m_globalUboScratch.clear();
m_attribs.clear();
m_attribTypes.clear();
m_activeUniformCount = 0;
m_maxUniformLocation = 0;
m_uniformNameMaxLength = 0;
m_attribInNameMaxLength = 0;
m_uniformBlockNameMaxLength = 0;
m_linkStatus = false;
}
bool ProgramObject::ShaderIsAttached(const SharedPtr<ShaderObject>& shader) {
MGLOG_D("ProgramObject %u: ShaderIsAttached check for shader %p", m_externalIndex, shader.get());
auto it = std::find_if(m_shaders.begin(), m_shaders.end(),
@@ -135,6 +156,8 @@ namespace MobileGL::MG_State::GLState {
void ProgramObject::Link(Bool addDefaultFSIfMissingForRenderingPipelineProgram) {
MGLOG_D("ProgramObject %u: Link start, shaders to link: %zu", m_externalIndex, m_shaders.size());
++m_backendStateVersion;
ResetLinkArtifacts();
m_infoLog.clear();
// Remove detached shaders first
for (const auto& detachedShader : m_detachedShaders) {
RemoveShader(detachedShader);
@@ -163,7 +186,6 @@ namespace MobileGL::MG_State::GLState {
"log:\n{}\nShader src:\n{}",
MG_Util::ConvertGLEnumToString(shaderTypes[i]), m_shaders[i]->GetInfoLog(),
m_shaders[i]->GetShaderSource());
m_linkStatus = false;
MGLOG_E("ProgramObject %u: Link failed - shader[%zu] compile status false. InfoLog:\n%s",
m_externalIndex, i, m_infoLog.c_str());
return;
@@ -186,9 +208,9 @@ namespace MobileGL::MG_State::GLState {
m_program = result.value();
MGLOG_D("ProgramObject %u: LinkProgram succeeded, TProgram ptr %p", m_externalIndex, m_program.get());
} else {
m_linkStatus = false;
m_infoLog = result.error().log;
MGLOG_E("ProgramObject %u: LinkProgram failed. InfoLog:\n%s", m_externalIndex, m_infoLog.c_str());
return;
}
MGLOG_D("ProgramObject %u: Starting reflection", m_externalIndex);
@@ -40,11 +40,40 @@ namespace MobileGL::MG_State::GLState {
return (Int)it->second;
}
Int GetActiveUniformIndex(const String& name) const {
const Int uniformIndex = m_program->getUniformIndex(name.c_str());
if (uniformIndex < 0 || uniformIndex >= m_activeUniformCount) return -1;
return m_program->getUniform(uniformIndex).name == name ? uniformIndex : -1;
}
Bool IsValidUniformLocation(Int location) const {
if (location < 0 || location > static_cast<Int>(m_maxUniformLocation)) return false;
if (static_cast<SizeT>(location) >= m_uniformIndexInTProgram.size()) return false;
const Int uniformIndexInProgram = m_uniformIndexInTProgram[location];
return uniformIndexInProgram != glslang::TQualifier::layoutLocationEnd &&
uniformIndexInProgram >= 0 && uniformIndexInProgram < m_activeUniformCount;
}
GLenum GetUniformType(Uint location) const {
auto& uniform = m_program->getUniform(m_uniformIndexInTProgram[location]);
return uniform.glDefineType;
}
GLenum GetActiveUniformType(Uint index) const {
auto& uniform = m_program->getUniform(static_cast<Int>(index));
return uniform.glDefineType;
}
GLint GetActiveUniformArraySize(Uint index) const {
auto& uniform = m_program->getUniform(static_cast<Int>(index));
return uniform.size;
}
Int GetActiveUniformBlockIndex(Uint index) const {
auto& uniform = m_program->getUniform(static_cast<Int>(index));
return uniform.index;
}
const glslang::TType* GetUniformTType(Uint location) const {
auto& uniform = m_program->getUniform(m_uniformIndexInTProgram[location]);
return uniform.getType();
@@ -56,6 +85,11 @@ namespace MobileGL::MG_State::GLState {
auto& uniform = m_program->getUniform(m_uniformIndexInTProgram[location]);
return uniform.name;
}
const String& GetActiveUniformName(Uint index) const {
auto& uniform = m_program->getUniform(static_cast<Int>(index));
return uniform.name;
}
Uint GetUniformOffset(Uint location) const { return m_uniformOffsets[location]; }
Uint GetUniformSizesInBytes(Uint location) const { return MG_Util::GetGLTypeSize(GetUniformType(location)); }
@@ -107,6 +141,9 @@ namespace MobileGL::MG_State::GLState {
}
GLenum GetAttribType(Uint index) const { return m_attribTypes[index]; }
const String& GetAttribName(Uint index) const { return m_attribs[index]; }
GLenum GetActiveAttribType(Uint index) const { return m_program->getPipeInput(static_cast<Int>(index)).glDefineType; }
GLint GetActiveAttribArraySize(Uint index) const { return m_program->getPipeInput(static_cast<Int>(index)).size; }
const String& GetActiveAttribName(Uint index) const { return m_program->getPipeInput(static_cast<Int>(index)).name; }
void* MapUBO() { return m_globalUboScratch.data(); }
const void* GetUBOData() const { return m_globalUboScratch.data(); }
Uint GetUBOSize() const { return static_cast<Uint>(m_globalUboScratch.size()); }
@@ -126,6 +163,7 @@ namespace MobileGL::MG_State::GLState {
Int GetActiveAtomicCounterCount() const { return m_program->getNumAtomicCounters(); }
Int GetActiveAttributesCount() const { return m_program->getNumPipeInputs(); }
Int GetActiveUniformBlocksCount() const { return m_program->getNumUniformBlocks(); }
GLuint GetComputeLocalSize(Uint dim) const { return m_program->getLocalSize(static_cast<Int>(dim)); }
Int GetActiveAttributesMaxLength() const { return m_attribInNameMaxLength; }
Int GetActiveUniformBlocksMaxNameLength() const { return m_uniformBlockNameMaxLength; }
Uint GetUniformBlockIndex(const char* name) const {
@@ -147,6 +185,16 @@ namespace MobileGL::MG_State::GLState {
return ubo.name;
}
Int GetUniformBlockActiveUniformCount(Uint index) const {
return m_program->getUniformBlock((Int)index).numMembers;
}
Bool IsUniformBlockReferencedByStage(Uint index, EShLanguage stage) const {
const auto& ubo = m_program->getUniformBlock((Int)index);
const auto stageMask = static_cast<EShLanguageMask>(1 << stage);
return (ubo.stages & stageMask) != 0;
}
// Set by glUniformBlockBinding
void SetUniformBlockBinding(Uint index, Uint binding) {
if (index >= m_uniformBlockBinding.size() || m_uniformBlockBinding[index] == static_cast<Int>(binding)) {
@@ -171,6 +219,7 @@ namespace MobileGL::MG_State::GLState {
Uint GetExternalIndex() const { return m_externalIndex; }
private:
void ResetLinkArtifacts();
void DoReflection();
void GenerateBinary();
void WaitUntilGenerationCompleted() const;
@@ -16,10 +16,16 @@
namespace MobileGL::MG_State::GLState {
void ShaderObject::SetShaderSource(const String& source) {
m_source = source;
m_shader.reset();
m_compileStatus = false;
m_infoLog.clear();
}
void ShaderObject::SetShaderSource(String&& source) {
m_source = Move(source);
m_shader.reset();
m_compileStatus = false;
m_infoLog.clear();
}
void ShaderObject::Compile() {
@@ -38,8 +44,10 @@ namespace MobileGL::MG_State::GLState {
if (result) {
m_compileStatus = true;
m_shader = result.value();
m_infoLog.clear();
} else {
m_compileStatus = false;
m_shader.reset();
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.",
@@ -12,6 +12,20 @@
namespace MobileGL {
namespace MG_State {
namespace GLState {
namespace {
SizeT GetStencilFaceIndex(StencilFace face) {
switch (face) {
case StencilFace::Front:
return 0;
case StencilFace::Back:
return 1;
default:
MOBILEGL_ASSERT(false, "Invalid stencil face enum: %d", static_cast<int>(face));
return 0;
}
}
} // namespace
RenderState::RenderState() {}
Uint RenderState::GetVersion() const {
@@ -34,6 +48,44 @@ namespace MobileGL {
return m_parameters.Viewport;
}
void RenderState::SetLineWidth(Float width) {
if (m_parameters.LineWidth == width) return;
m_parameters.LineWidth = width;
++m_version;
}
Float RenderState::GetLineWidth() const {
return m_parameters.LineWidth;
}
void RenderState::SetPointSize(Float size) {
if (m_parameters.PointSize == size) return;
m_parameters.PointSize = size;
++m_version;
}
Float RenderState::GetPointSize() const {
return m_parameters.PointSize;
}
void RenderState::SetPolygonOffset(Float factor, Float units) {
if (m_parameters.PolygonOffsetFactor == factor && m_parameters.PolygonOffsetUnits == units) return;
m_parameters.PolygonOffsetFactor = factor;
m_parameters.PolygonOffsetUnits = units;
++m_version;
}
Float RenderState::GetPolygonOffsetFactor() const {
return m_parameters.PolygonOffsetFactor;
}
Float RenderState::GetPolygonOffsetUnits() const {
return m_parameters.PolygonOffsetUnits;
}
// -------------------- Capabilities --------------------
void RenderState::SetCapability(CapabilityInput cap, Bool enabled) {
#define SET_CAPABILITY(capability, flag) \
@@ -44,9 +96,28 @@ namespace MobileGL {
break;
switch (cap) {
SET_CAPABILITY(ColorLogicOp, enabled);
SET_CAPABILITY(DebugOutput, enabled);
SET_CAPABILITY(DebugOutputSynchronous, enabled);
SET_CAPABILITY(DepthTest, enabled);
SET_CAPABILITY(CullFace, enabled);
SET_CAPABILITY(Dither, enabled);
SET_CAPABILITY(LineSmooth, enabled);
SET_CAPABILITY(Multisample, enabled);
SET_CAPABILITY(PolygonOffsetFill, enabled);
SET_CAPABILITY(PolygonOffsetLine, enabled);
SET_CAPABILITY(PolygonOffsetPoint, enabled);
SET_CAPABILITY(PolygonSmooth, enabled);
SET_CAPABILITY(PrimitiveRestart, enabled);
SET_CAPABILITY(PrimitiveRestartFixedIndex, enabled);
SET_CAPABILITY(RasterizerDiscard, enabled);
SET_CAPABILITY(SampleAlphaToCoverage, enabled);
SET_CAPABILITY(SampleAlphaToOne, enabled);
SET_CAPABILITY(SampleCoverage, enabled);
SET_CAPABILITY(SampleMask, enabled);
SET_CAPABILITY(ScissorTest, enabled);
SET_CAPABILITY(StencilTest, enabled);
SET_CAPABILITY(ProgramPointSize, enabled);
case CapabilityInput::Blend: {
Bool stateChanged = false;
for (auto& blendState : m_parameters.BlendStates) {
@@ -68,9 +139,28 @@ namespace MobileGL {
case CapabilityInput::capability: \
return m_parameters.capability##Enabled;
switch (cap) {
RETURN_CAPABILITY(ColorLogicOp);
RETURN_CAPABILITY(DebugOutput);
RETURN_CAPABILITY(DebugOutputSynchronous);
RETURN_CAPABILITY(DepthTest);
RETURN_CAPABILITY(CullFace);
RETURN_CAPABILITY(Dither);
RETURN_CAPABILITY(LineSmooth);
RETURN_CAPABILITY(Multisample);
RETURN_CAPABILITY(PolygonOffsetFill);
RETURN_CAPABILITY(PolygonOffsetLine);
RETURN_CAPABILITY(PolygonOffsetPoint);
RETURN_CAPABILITY(PolygonSmooth);
RETURN_CAPABILITY(PrimitiveRestart);
RETURN_CAPABILITY(PrimitiveRestartFixedIndex);
RETURN_CAPABILITY(RasterizerDiscard);
RETURN_CAPABILITY(SampleAlphaToCoverage);
RETURN_CAPABILITY(SampleAlphaToOne);
RETURN_CAPABILITY(SampleCoverage);
RETURN_CAPABILITY(SampleMask);
RETURN_CAPABILITY(ScissorTest);
RETURN_CAPABILITY(StencilTest);
RETURN_CAPABILITY(ProgramPointSize);
case CapabilityInput::Blend:
return m_parameters.BlendStates[0].Enabled;
default:
@@ -206,6 +296,17 @@ namespace MobileGL {
alpha = m_parameters.BlendStates[index].AlphaEquation;
}
void RenderState::SetLogicOp(LogicOperation logicOp) {
if (m_parameters.LogicOp == logicOp) return;
m_parameters.LogicOp = logicOp;
++m_version;
}
LogicOperation RenderState::GetLogicOp() const {
return m_parameters.LogicOp;
}
// -------------------- Depth --------------------
void RenderState::SetDepthFunc(DepthTestFunc func) {
if (m_parameters.DepthFunc == func) return;
@@ -229,6 +330,42 @@ namespace MobileGL {
return m_parameters.DepthMask;
}
void RenderState::SetStencilFunc(StencilFace face, DepthTestFunc func, Int ref, Uint32 mask) {
StencilFaceState& state = m_parameters.StencilStates[GetStencilFaceIndex(face)];
if (state.Func == func && state.Ref == ref && state.ValueMask == mask) return;
state.Func = func;
state.Ref = ref;
state.ValueMask = mask;
++m_version;
}
void RenderState::SetStencilMask(StencilFace face, Uint32 mask) {
StencilFaceState& state = m_parameters.StencilStates[GetStencilFaceIndex(face)];
if (state.WriteMask == mask) return;
state.WriteMask = mask;
++m_version;
}
void RenderState::SetStencilOp(StencilFace face, StencilOperation fail, StencilOperation depthFail,
StencilOperation depthPass) {
StencilFaceState& state = m_parameters.StencilStates[GetStencilFaceIndex(face)];
if (state.FailOp == fail && state.PassDepthFailOp == depthFail &&
state.PassDepthPassOp == depthPass) {
return;
}
state.FailOp = fail;
state.PassDepthFailOp = depthFail;
state.PassDepthPassOp = depthPass;
++m_version;
}
const StencilFaceState& RenderState::GetStencilState(StencilFace face) const {
return m_parameters.StencilStates[GetStencilFaceIndex(face)];
}
// -------------------- Color Mask --------------------
void RenderState::SetColorMask(BoolVec4 mask) {
if (m_parameters.ColorMask == mask) return;
@@ -275,6 +412,55 @@ namespace MobileGL {
return m_parameters.ClearStencil;
}
void RenderState::SetBlendColor(FloatVec4 color) {
if (m_parameters.BlendColor == color) return;
m_parameters.BlendColor = color;
++m_version;
}
const FloatVec4& RenderState::GetBlendColor() const {
return m_parameters.BlendColor;
}
void RenderState::SetDepthRange(FloatVec2 range) {
if (m_parameters.DepthRange == range) return;
m_parameters.DepthRange = range;
++m_version;
}
const FloatVec2& RenderState::GetDepthRange() const {
return m_parameters.DepthRange;
}
void RenderState::SetSampleCoverage(Float value, Bool invert) {
if (m_parameters.SampleCoverageValue == value && m_parameters.SampleCoverageInvert == invert) return;
m_parameters.SampleCoverageValue = value;
m_parameters.SampleCoverageInvert = invert;
++m_version;
}
Float RenderState::GetSampleCoverageValue() const {
return m_parameters.SampleCoverageValue;
}
Bool RenderState::GetSampleCoverageInvert() const {
return m_parameters.SampleCoverageInvert;
}
void RenderState::SetSampleMaskValue(Uint32 mask) {
if (m_parameters.SampleMaskValue == mask) return;
m_parameters.SampleMaskValue = mask;
++m_version;
}
Uint32 RenderState::GetSampleMaskValue() const {
return m_parameters.SampleMaskValue;
}
// -------------------- Pixel Store --------------------
void RenderState::SetPixelStoreParam(PixelStoreParam param, Int value) {
#define SET_PIXEL_STORE_PARAM(paramNameHead, paramNameTail, val) \
@@ -41,6 +41,27 @@ namespace MobileGL {
Unknown = -1
};
enum class LogicOperation {
Clear,
And,
AndReverse,
Copy,
AndInverted,
Noop,
Xor,
Or,
Nor,
Equiv,
Invert,
OrReverse,
CopyInverted,
OrInverted,
Nand,
Set,
LogicOperationCount,
Unknown = -1
};
enum class DepthTestFunc {
Never,
Less,
@@ -54,6 +75,26 @@ namespace MobileGL {
Unknown = -1
};
enum class StencilOperation {
Keep,
Zero,
Replace,
IncrementClamp,
DecrementClamp,
Invert,
IncrementWrap,
DecrementWrap,
StencilOperationCount,
Unknown = -1
};
enum class StencilFace {
Front,
Back,
StencilFaceCount,
Unknown = -1
};
enum class PixelStoreParam {
// Pack Parameters
PackAlignment,
@@ -155,12 +196,27 @@ namespace MobileGL {
BlendEquation AlphaEquation = BlendEquation::Add;
};
struct StencilFaceState {
DepthTestFunc Func = DepthTestFunc::Always;
Int Ref = 0;
Uint32 ValueMask = 0xffffffffu;
Uint32 WriteMask = 0xffffffffu;
StencilOperation FailOp = StencilOperation::Keep;
StencilOperation PassDepthFailOp = StencilOperation::Keep;
StencilOperation PassDepthPassOp = StencilOperation::Keep;
};
struct RenderStateParameters {
// Rasterization
IntVec4 Viewport = IntVec4(0, 0, 0, 0); // x, y, width, height
Float LineWidth = 1.0f;
Float PointSize = 1.0f;
Float PolygonOffsetFactor = 0.0f;
Float PolygonOffsetUnits = 0.0f;
// Blending
Array<PerBufferBlendState, MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS> BlendStates;
LogicOperation LogicOp = LogicOperation::Copy;
// Depth
Bool DepthTestEnabled = false;
@@ -174,6 +230,12 @@ namespace MobileGL {
FloatVec4 ClearColor = FloatVec4(0.0f, 0.0f, 0.0f, 1.0f);
Float ClearDepth = 1.0f;
Uint32 ClearStencil = 0;
FloatVec4 BlendColor = FloatVec4(0.0f, 0.0f, 0.0f, 0.0f);
FloatVec2 DepthRange = FloatVec2(0.0f, 1.0f);
Float SampleCoverageValue = 1.0f;
Bool SampleCoverageInvert = false;
Uint32 SampleMaskValue = 0xffffffffu;
Array<StencilFaceState, 2> StencilStates{};
// Cull Face
Bool CullFaceEnabled = false;
@@ -181,7 +243,26 @@ namespace MobileGL {
FrontFaceMode FrontFaceModeSetting = FrontFaceMode::CounterClockwise;
// Scissor
Bool ColorLogicOpEnabled = false;
Bool DebugOutputEnabled = false;
Bool DebugOutputSynchronousEnabled = false;
Bool DitherEnabled = true;
Bool LineSmoothEnabled = false;
Bool MultisampleEnabled = true;
Bool PolygonOffsetFillEnabled = false;
Bool PolygonOffsetLineEnabled = false;
Bool PolygonOffsetPointEnabled = false;
Bool PolygonSmoothEnabled = false;
Bool PrimitiveRestartEnabled = false;
Bool PrimitiveRestartFixedIndexEnabled = false;
Bool RasterizerDiscardEnabled = false;
Bool SampleAlphaToCoverageEnabled = false;
Bool SampleAlphaToOneEnabled = false;
Bool SampleCoverageEnabled = false;
Bool SampleMaskEnabled = false;
Bool ScissorTestEnabled = false;
Bool StencilTestEnabled = false;
Bool ProgramPointSizeEnabled = false;
IntVec4 ScissorBox = IntVec4(0, 0, 0, 0); // x, y, width, height
};
@@ -197,6 +278,13 @@ namespace MobileGL {
// Rasterization
void SetViewport(IntVec4 viewport); // x, y, width, height
const IntVec4& GetViewport() const; // x, y, width, height
void SetLineWidth(Float width);
Float GetLineWidth() const;
void SetPointSize(Float size);
Float GetPointSize() const;
void SetPolygonOffset(Float factor, Float units);
Float GetPolygonOffsetFactor() const;
Float GetPolygonOffsetUnits() const;
// Capabilities
void SetCapability(CapabilityInput cap, Bool enabled);
@@ -216,12 +304,19 @@ namespace MobileGL {
void GetBlendEquation(BlendEquation& color, BlendEquation& alpha) const;
void SetBlendEquationIndexed(Uint index, BlendEquation color, BlendEquation alpha);
void GetBlendEquationIndexed(Uint index, BlendEquation& color, BlendEquation& alpha) const;
void SetLogicOp(LogicOperation logicOp);
LogicOperation GetLogicOp() const;
// Depth
void SetDepthFunc(DepthTestFunc func);
DepthTestFunc GetDepthFunc() const;
void SetDepthMask(Bool flag);
Bool GetDepthMask() const;
void SetStencilFunc(StencilFace face, DepthTestFunc func, Int ref, Uint32 mask);
void SetStencilMask(StencilFace face, Uint32 mask);
void SetStencilOp(StencilFace face, StencilOperation fail, StencilOperation depthFail,
StencilOperation depthPass);
const StencilFaceState& GetStencilState(StencilFace face) const;
// Color Mask
void SetColorMask(BoolVec4 mask);
@@ -234,6 +329,15 @@ namespace MobileGL {
Float GetClearDepth() const;
void SetClearStencil(Int stencil);
Uint32 GetClearStencil() const;
void SetBlendColor(FloatVec4 color);
const FloatVec4& GetBlendColor() const;
void SetDepthRange(FloatVec2 range);
const FloatVec2& GetDepthRange() const;
void SetSampleCoverage(Float value, Bool invert);
Float GetSampleCoverageValue() const;
Bool GetSampleCoverageInvert() const;
void SetSampleMaskValue(Uint32 mask);
Uint32 GetSampleMaskValue() const;
// Pixel Store
void SetPixelStoreParam(PixelStoreParam param, Int value);
@@ -76,6 +76,10 @@ namespace MobileGL {
m_height = size.y();
m_allocated = true;
}
void RenderbufferObject::SetSamples(Int samples) {
m_samples = samples;
}
} // namespace GLState
} // namespace MG_State
} // namespace MobileGL
@@ -29,6 +29,7 @@ namespace MobileGL {
Uint GetExternalIndex() const;
void SetInternalFormat(TextureInternalFormat format);
void AllocateStorage(IntVec2 size);
void SetSamples(Int samples);
Int GetWidth() const;
Int GetHeight() const;
TextureInternalFormat GetInternalFormat() const;
@@ -47,7 +48,7 @@ namespace MobileGL {
TextureInternalFormat m_internalFormat;
Int m_width = 0;
Int m_height = 0;
Int m_samples = 0; // TODO: multisampling support
Int m_samples = 0;
Bool m_allocated = false;
ComponentSizes m_componentSizes;
};
@@ -57,10 +57,6 @@ namespace MobileGL {
void SamplerObject::SetLodRange(Float minLod, Float maxLod) {
if (minLod == m_samplerParameters.minLod && maxLod == m_samplerParameters.maxLod) return;
if (minLod > maxLod) {
THROW_EXCEPTION("minLod cannot be greater than maxLod");
}
m_samplerParameters.minLod = minLod;
m_samplerParameters.maxLod = maxLod;
++m_version;
@@ -50,7 +50,7 @@ namespace MobileGL {
Uint TextureObject2DCube::GetIndexOfTextureUploadTarget(TextureUploadTarget target) const {
MOBILEGL_ASSERT(TextureUploadTarget::CubeMapPositiveX <= target &&
target <= TextureUploadTarget::ProxyCubeMap,
target <= TextureUploadTarget::CubeMapNegativeZ,
"Invalid TextureUploadTarget!");
return (Uint)target - (Uint)TextureUploadTarget::CubeMapPositiveX;
}
@@ -50,8 +50,8 @@ namespace MobileGL::MG_State::GLState {
void VertexArrayState::MarkVertexArrayForDeletion(Uint index) {
if (m_indexGenerator.IsValid(index)) {
if (m_boundVertexArray) {
m_boundVertexArray = nullptr;
if (m_boundVertexArray && m_boundVertexArray->GetExternalIndex() == index) {
m_boundVertexArray = GetVertexArrayObject(0);
}
if (ValidateVertexArrayObject(index)) {
@@ -46,6 +46,8 @@ TEST(DirectVulkanSanity, WindowCreation) {
#include <EGL/egl.h>
#ifdef _WIN32
#define GLFW_EXPOSE_NATIVE_WIN32
#elif defined(__linux__)
#define GLFW_EXPOSE_NATIVE_X11
#elif defined(__APPLE__)
#define GLFW_EXPOSE_NATIVE_COCOA
#endif
@@ -74,9 +76,11 @@ TEST(DirectVulkanSanity, ContextCreation) {
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(800, 600, "MobileGL ContextCreation", nullptr, nullptr);
EGLNativeWindowType nativewindow = nullptr;
EGLNativeWindowType nativewindow = 0;
#ifdef _WIN32
nativewindow = glfwGetWin32Window(window);
#elif defined(__linux__)
nativewindow = static_cast<EGLNativeWindowType>(glfwGetX11Window(window));
#elif defined(__APPLE__)
void* cocoaWindow = glfwGetCocoaWindow(window);
ASSERT_NE(cocoaWindow, nullptr);
@@ -95,6 +99,7 @@ TEST(DirectVulkanSanity, ContextCreation) {
msgSendVoidObj(contentView, sel_registerName("setLayer:"), metalLayer);
nativewindow = reinterpret_cast<EGLNativeWindowType>(metalLayer);
#endif
ASSERT_NE(nativewindow, static_cast<EGLNativeWindowType>(0));
EGLSurface surface = eglCreateWindowSurface(display, config, nativewindow, nullptr);
eglMakeCurrent(display, surface, surface, context);
@@ -28,6 +28,8 @@
#include <EGL/egl.h>
#ifdef _WIN32
#define GLFW_EXPOSE_NATIVE_WIN32
#elif defined(__linux__)
#define GLFW_EXPOSE_NATIVE_X11
#elif defined(__APPLE__)
#define GLFW_EXPOSE_NATIVE_COCOA
#endif
@@ -107,9 +109,11 @@ int main() {
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(800, 600, "MobileGL ContextCreation", nullptr, nullptr);
EGLNativeWindowType nativewindow = nullptr;
EGLNativeWindowType nativewindow = 0;
#ifdef _WIN32
nativewindow = glfwGetWin32Window(window);
#elif defined(__linux__)
nativewindow = static_cast<EGLNativeWindowType>(glfwGetX11Window(window));
#elif defined(__APPLE__)
void* cocoaWindow = glfwGetCocoaWindow(window);
MOBILEGL_ASSERT(cocoaWindow, "glfwGetCocoaWindow returned null");
@@ -128,6 +132,7 @@ int main() {
msgSendVoidObj(contentView, sel_registerName("setLayer:"), metalLayer);
nativewindow = reinterpret_cast<EGLNativeWindowType>(metalLayer);
#endif
MOBILEGL_ASSERT(nativewindow, "Failed to acquire native window handle for EGL window surface creation");
EGLSurface surface = eglCreateWindowSurface(display, config, nativewindow, nullptr);
eglMakeCurrent(display, surface, surface, context);
@@ -48,11 +48,14 @@ namespace MobileGL::MG_Util::BackendLoader {
return false;
}
Bool allRequiredLoaded = true;
#define INIT_GLES_FUNC(name) \
do { \
funcs.name = (MG_External::GLES::name##_PTR)procAddress(#name); \
if (!funcs.name) { \
MGLOG_E("Failed to load GLES function: %s", #name); \
allRequiredLoaded = false; \
} \
} while (0);
@@ -149,6 +152,8 @@ namespace MobileGL::MG_Util::BackendLoader {
INIT_GLES_FUNC(glIsTexture)
INIT_GLES_FUNC(glLineWidth)
INIT_GLES_FUNC(glLinkProgram)
INIT_GLES_FUNC(glLogicOp)
INIT_GLES_FUNC(glPointSize)
INIT_GLES_FUNC(glPixelStorei)
INIT_GLES_FUNC(glPolygonOffset)
INIT_GLES_FUNC(glReadPixels)
@@ -428,7 +433,7 @@ namespace MobileGL::MG_Util::BackendLoader {
INIT_GLES_FUNC(glMultiDrawElementsIndirectEXT)
INIT_GLES_FUNC(glMultiDrawElementsBaseVertexEXT)
}
return true;
return allRequiredLoaded;
}
Bool AcquireEGLFunctions(MG_External::EGLFunctionsTable& funcs) {
@@ -438,11 +443,15 @@ namespace MobileGL::MG_Util::BackendLoader {
MGLOG_E("Failed to open libEGL.so");
return false;
}
Bool allRequiredLoaded = true;
#define INIT_EGL_FUNC(name) \
do { \
funcs.name = (MG_External::EGL::name##_PTR)ProcAddress(eglLib, #name); \
if (!funcs.name) { \
MGLOG_E("Failed to load EGL function: %s", #name); \
allRequiredLoaded = false; \
} \
} while (0);
@@ -495,7 +504,7 @@ namespace MobileGL::MG_Util::BackendLoader {
INIT_EGL_FUNC(eglGetPlatformDisplay)
INIT_EGL_FUNC(eglWaitSync)
}
return true;
return allRequiredLoaded;
}
Bool FillInGLESCapabilities(MG_External::GLESCapabilities& caps, const MG_External::GLESFunctionsTable& glesFuncs) {
@@ -535,6 +544,179 @@ namespace MobileGL::MG_Util::BackendLoader {
MGLOG_I("OpenGL ES capabilities:");
glesFuncs.glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &caps.UniformBufferOffsetAlignment);
MGLOG_I(" GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: %d", caps.UniformBufferOffsetAlignment);
GLfloat aliasedLineWidthRange[2] = {1.0f, 1.0f};
GLfloat smoothLineWidthRange[2] = {1.0f, 1.0f};
GLfloat smoothLineWidthGranularity = 1.0f;
GLfloat aliasedPointSizeRange[2] = {1.0f, 1.0f};
GLfloat viewportBoundsRange[2] = {0.0f, 0.0f};
GLint maxViewportDims[2] = {16384, 16384};
GLint viewportSubpixelBits = 0;
GLint max3DTextureSize = 16384;
GLint maxArrayTextureLayers = 2048;
GLint maxCubeMapTextureSize = 16384;
GLint maxFramebufferWidth = 16384;
GLint maxFramebufferHeight = 16384;
GLint maxFramebufferLayers = 2048;
GLint maxRenderbufferSize = 16384;
GLint maxTextureSize = 16384;
GLint maxColorTextureSamples = 1;
GLint maxDepthTextureSamples = 1;
GLint maxFramebufferSamples = 1;
GLint maxIntegerSamples = 1;
GLint maxSamples = 1;
GLint maxSampleMaskWords = 1;
GLint maxTextureImageUnits = 32;
GLint maxVertexTextureImageUnits = 32;
GLint maxComputeTextureImageUnits = 32;
GLint maxCombinedTextureImageUnits = 192;
GLint maxVertexAttribs = 16;
GLint maxComputeShaderStorageBlocks = 8;
GLint maxCombinedShaderStorageBlocks = 32;
GLint maxComputeUniformBlocks = 12;
GLint maxComputeWorkGroupInvocations = 128;
GLint maxShaderStorageBufferBindings = 8;
GLint maxTextureBufferSize = 65536;
GLint maxUniformBufferBindings = 24;
GLint maxUniformBlockSize = 16384;
GLint maxImageUnits = 8;
GLint maxCombinedImageUniforms = 8;
GLint maxComputeImageUniforms = 8;
GLint maxDrawBuffers = 8;
GLint maxColorAttachments = 8;
GLint maxClipDistances = 8;
GLint maxViewports = 16;
glesFuncs.glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, aliasedLineWidthRange);
glesFuncs.glGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, smoothLineWidthRange);
glesFuncs.glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &smoothLineWidthGranularity);
glesFuncs.glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, aliasedPointSizeRange);
glesFuncs.glGetFloatv(GL_VIEWPORT_BOUNDS_RANGE, viewportBoundsRange);
glesFuncs.glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max3DTextureSize);
glesFuncs.glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxArrayTextureLayers);
glesFuncs.glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &maxCubeMapTextureSize);
glesFuncs.glGetIntegerv(GL_MAX_FRAMEBUFFER_WIDTH, &maxFramebufferWidth);
glesFuncs.glGetIntegerv(GL_MAX_FRAMEBUFFER_HEIGHT, &maxFramebufferHeight);
glesFuncs.glGetIntegerv(GL_MAX_FRAMEBUFFER_LAYERS, &maxFramebufferLayers);
glesFuncs.glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxRenderbufferSize);
glesFuncs.glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
glesFuncs.glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &maxColorTextureSamples);
glesFuncs.glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &maxDepthTextureSamples);
glesFuncs.glGetIntegerv(GL_MAX_FRAMEBUFFER_SAMPLES, &maxFramebufferSamples);
glesFuncs.glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &maxIntegerSamples);
glesFuncs.glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
glesFuncs.glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords);
glesFuncs.glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureImageUnits);
glesFuncs.glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextureImageUnits);
glesFuncs.glGetIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, &maxComputeTextureImageUnits);
glesFuncs.glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxCombinedTextureImageUnits);
glesFuncs.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
glesFuncs.glGetIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &maxComputeShaderStorageBlocks);
glesFuncs.glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &maxCombinedShaderStorageBlocks);
glesFuncs.glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_BLOCKS, &maxComputeUniformBlocks);
glesFuncs.glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &maxComputeWorkGroupInvocations);
glesFuncs.glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxShaderStorageBufferBindings);
glesFuncs.glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &maxTextureBufferSize);
glesFuncs.glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBufferBindings);
glesFuncs.glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
glesFuncs.glGetIntegerv(GL_MAX_IMAGE_UNITS, &maxImageUnits);
glesFuncs.glGetIntegerv(GL_MAX_COMBINED_IMAGE_UNIFORMS, &maxCombinedImageUniforms);
glesFuncs.glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &maxComputeImageUniforms);
glesFuncs.glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
glesFuncs.glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxColorAttachments);
glesFuncs.glGetIntegerv(GL_MAX_CLIP_DISTANCES, &maxClipDistances);
glesFuncs.glGetIntegerv(GL_MAX_VIEWPORTS, &maxViewports);
glesFuncs.glGetIntegerv(GL_MAX_VIEWPORT_DIMS, maxViewportDims);
glesFuncs.glGetIntegerv(GL_VIEWPORT_SUBPIXEL_BITS, &viewportSubpixelBits);
caps.AliasedLineWidthRangeMin = aliasedLineWidthRange[0];
caps.AliasedLineWidthRangeMax = aliasedLineWidthRange[1];
caps.SmoothLineWidthRangeMin = smoothLineWidthRange[0];
caps.SmoothLineWidthRangeMax = smoothLineWidthRange[1];
caps.SmoothLineWidthGranularity = smoothLineWidthGranularity;
caps.PointSizeRangeMin = aliasedPointSizeRange[0];
caps.PointSizeRangeMax = aliasedPointSizeRange[1];
caps.PointSizeGranularity = 1.0f;
caps.Max3DTextureSize = max3DTextureSize;
caps.MaxArrayTextureLayers = maxArrayTextureLayers;
caps.MaxCubeMapTextureSize = maxCubeMapTextureSize;
caps.MaxFramebufferWidth = maxFramebufferWidth;
caps.MaxFramebufferHeight = maxFramebufferHeight;
caps.MaxFramebufferLayers = maxFramebufferLayers;
caps.MaxRenderbufferSize = maxRenderbufferSize;
caps.MaxTextureSize = maxTextureSize;
caps.MaxColorTextureSamples = maxColorTextureSamples;
caps.MaxDepthTextureSamples = maxDepthTextureSamples;
caps.MaxFramebufferSamples = maxFramebufferSamples;
caps.MaxIntegerSamples = maxIntegerSamples;
caps.MaxSamples = maxSamples;
caps.MaxSampleMaskWords = maxSampleMaskWords;
caps.MaxTextureImageUnits = maxTextureImageUnits;
caps.MaxVertexTextureImageUnits = maxVertexTextureImageUnits;
caps.MaxComputeTextureImageUnits = maxComputeTextureImageUnits;
caps.MaxCombinedTextureImageUnits = maxCombinedTextureImageUnits;
caps.MaxVertexAttribs = maxVertexAttribs;
caps.MaxComputeShaderStorageBlocks = maxComputeShaderStorageBlocks;
caps.MaxCombinedShaderStorageBlocks = maxCombinedShaderStorageBlocks;
caps.MaxComputeUniformBlocks = maxComputeUniformBlocks;
caps.MaxComputeWorkGroupInvocations = maxComputeWorkGroupInvocations;
caps.MaxShaderStorageBufferBindings = maxShaderStorageBufferBindings;
caps.MaxTextureBufferSize = maxTextureBufferSize;
caps.MaxUniformBufferBindings = maxUniformBufferBindings;
caps.MaxUniformBlockSize = maxUniformBlockSize;
caps.MaxImageUnits = maxImageUnits;
caps.MaxCombinedImageUniforms = maxCombinedImageUniforms;
caps.MaxComputeImageUniforms = maxComputeImageUniforms;
caps.MaxDrawBuffers = maxDrawBuffers;
caps.MaxColorAttachments = maxColorAttachments;
caps.MaxClipDistances = maxClipDistances;
caps.MaxViewports = maxViewports;
caps.MaxViewportWidth = maxViewportDims[0];
caps.MaxViewportHeight = maxViewportDims[1];
caps.ViewportBoundsRangeMin = viewportBoundsRange[0];
caps.ViewportBoundsRangeMax = viewportBoundsRange[1];
caps.ViewportSubpixelBits = viewportSubpixelBits;
MGLOG_I(" GL_ALIASED_LINE_WIDTH_RANGE: [%.3f, %.3f]", caps.AliasedLineWidthRangeMin,
caps.AliasedLineWidthRangeMax);
MGLOG_I(" GL_SMOOTH_LINE_WIDTH_RANGE: [%.3f, %.3f]", caps.SmoothLineWidthRangeMin,
caps.SmoothLineWidthRangeMax);
MGLOG_I(" GL_SMOOTH_LINE_WIDTH_GRANULARITY: %.3f", caps.SmoothLineWidthGranularity);
MGLOG_I(" GL_ALIASED_POINT_SIZE_RANGE: [%.3f, %.3f]", caps.PointSizeRangeMin, caps.PointSizeRangeMax);
MGLOG_I(" GL_MAX_3D_TEXTURE_SIZE: %d", caps.Max3DTextureSize);
MGLOG_I(" GL_MAX_ARRAY_TEXTURE_LAYERS: %d", caps.MaxArrayTextureLayers);
MGLOG_I(" GL_MAX_CUBE_MAP_TEXTURE_SIZE: %d", caps.MaxCubeMapTextureSize);
MGLOG_I(" GL_MAX_FRAMEBUFFER_WIDTH: %d", caps.MaxFramebufferWidth);
MGLOG_I(" GL_MAX_FRAMEBUFFER_HEIGHT: %d", caps.MaxFramebufferHeight);
MGLOG_I(" GL_MAX_FRAMEBUFFER_LAYERS: %d", caps.MaxFramebufferLayers);
MGLOG_I(" GL_MAX_RENDERBUFFER_SIZE: %d", caps.MaxRenderbufferSize);
MGLOG_I(" GL_MAX_TEXTURE_SIZE: %d", caps.MaxTextureSize);
MGLOG_I(" GL_MAX_COLOR_TEXTURE_SAMPLES: %d", caps.MaxColorTextureSamples);
MGLOG_I(" GL_MAX_DEPTH_TEXTURE_SAMPLES: %d", caps.MaxDepthTextureSamples);
MGLOG_I(" GL_MAX_FRAMEBUFFER_SAMPLES: %d", caps.MaxFramebufferSamples);
MGLOG_I(" GL_MAX_INTEGER_SAMPLES: %d", caps.MaxIntegerSamples);
MGLOG_I(" GL_MAX_SAMPLES: %d", caps.MaxSamples);
MGLOG_I(" GL_MAX_SAMPLE_MASK_WORDS: %d", caps.MaxSampleMaskWords);
MGLOG_I(" GL_MAX_TEXTURE_IMAGE_UNITS: %d", caps.MaxTextureImageUnits);
MGLOG_I(" GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: %d", caps.MaxVertexTextureImageUnits);
MGLOG_I(" GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS: %d", caps.MaxComputeTextureImageUnits);
MGLOG_I(" GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d", caps.MaxCombinedTextureImageUnits);
MGLOG_I(" GL_MAX_VERTEX_ATTRIBS: %d", caps.MaxVertexAttribs);
MGLOG_I(" GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS: %d", caps.MaxComputeShaderStorageBlocks);
MGLOG_I(" GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS: %d", caps.MaxCombinedShaderStorageBlocks);
MGLOG_I(" GL_MAX_COMPUTE_UNIFORM_BLOCKS: %d", caps.MaxComputeUniformBlocks);
MGLOG_I(" GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS: %d", caps.MaxComputeWorkGroupInvocations);
MGLOG_I(" GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS: %d", caps.MaxShaderStorageBufferBindings);
MGLOG_I(" GL_MAX_TEXTURE_BUFFER_SIZE: %d", caps.MaxTextureBufferSize);
MGLOG_I(" GL_MAX_UNIFORM_BUFFER_BINDINGS: %d", caps.MaxUniformBufferBindings);
MGLOG_I(" GL_MAX_UNIFORM_BLOCK_SIZE: %d", caps.MaxUniformBlockSize);
MGLOG_I(" GL_MAX_IMAGE_UNITS: %d", caps.MaxImageUnits);
MGLOG_I(" GL_MAX_COMBINED_IMAGE_UNIFORMS: %d", caps.MaxCombinedImageUniforms);
MGLOG_I(" GL_MAX_COMPUTE_IMAGE_UNIFORMS: %d", caps.MaxComputeImageUniforms);
MGLOG_I(" GL_MAX_DRAW_BUFFERS: %d", caps.MaxDrawBuffers);
MGLOG_I(" GL_MAX_COLOR_ATTACHMENTS: %d", caps.MaxColorAttachments);
MGLOG_I(" GL_MAX_CLIP_DISTANCES: %d", caps.MaxClipDistances);
MGLOG_I(" GL_MAX_VIEWPORTS: %d", caps.MaxViewports);
MGLOG_I(" GL_MAX_VIEWPORT_DIMS: [%d, %d]", caps.MaxViewportWidth, caps.MaxViewportHeight);
MGLOG_I(" GL_VIEWPORT_BOUNDS_RANGE: [%.3f, %.3f]", caps.ViewportBoundsRangeMin,
caps.ViewportBoundsRangeMax);
MGLOG_I(" GL_VIEWPORT_SUBPIXEL_BITS: %d", caps.ViewportSubpixelBits);
return true;
}
@@ -238,6 +238,8 @@ namespace MobileGL {
GL_FUNC_TYPEDEF(GLboolean, glIsTexture, GLuint texture)
GL_FUNC_TYPEDEF(void, glLineWidth, GLfloat width)
GL_FUNC_TYPEDEF(void, glLinkProgram, GLuint program)
GL_FUNC_TYPEDEF(void, glLogicOp, GLenum opcode)
GL_FUNC_TYPEDEF(void, glPointSize, GLfloat size)
GL_FUNC_TYPEDEF(void, glPixelStorei, GLenum pname, GLint param)
GL_FUNC_TYPEDEF(void, glPolygonOffset, GLfloat factor, GLfloat units)
GL_FUNC_TYPEDEF(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
@@ -725,6 +727,8 @@ namespace MobileGL {
GL_FUNC_DECL(glIsTexture)
GL_FUNC_DECL(glLineWidth)
GL_FUNC_DECL(glLinkProgram)
GL_FUNC_DECL(glLogicOp)
GL_FUNC_DECL(glPointSize)
GL_FUNC_DECL(glPixelStorei)
GL_FUNC_DECL(glPolygonOffset)
GL_FUNC_DECL(glReadPixels)
@@ -1015,6 +1019,53 @@ namespace MobileGL {
Bool SupportsPersistentMapping = false;
Bool SupportsNorm16Texture = false;
Int UniformBufferOffsetAlignment = 256;
Float AliasedLineWidthRangeMin = 1.0f;
Float AliasedLineWidthRangeMax = 1.0f;
Float SmoothLineWidthRangeMin = 1.0f;
Float SmoothLineWidthRangeMax = 1.0f;
Float SmoothLineWidthGranularity = 1.0f;
Float PointSizeRangeMin = 1.0f;
Float PointSizeRangeMax = 1.0f;
Float PointSizeGranularity = 1.0f;
Int Max3DTextureSize = 16384;
Int MaxArrayTextureLayers = 2048;
Int MaxCubeMapTextureSize = 16384;
Int MaxFramebufferWidth = 16384;
Int MaxFramebufferHeight = 16384;
Int MaxFramebufferLayers = 2048;
Int MaxRenderbufferSize = 16384;
Int MaxTextureSize = 16384;
Int MaxColorTextureSamples = 1;
Int MaxDepthTextureSamples = 1;
Int MaxFramebufferSamples = 1;
Int MaxIntegerSamples = 1;
Int MaxSamples = 1;
Int MaxSampleMaskWords = 1;
Int MaxTextureImageUnits = 32;
Int MaxVertexTextureImageUnits = 32;
Int MaxComputeTextureImageUnits = 32;
Int MaxCombinedTextureImageUnits = 192;
Int MaxVertexAttribs = 16;
Int MaxComputeShaderStorageBlocks = 8;
Int MaxCombinedShaderStorageBlocks = 32;
Int MaxComputeUniformBlocks = 12;
Int MaxComputeWorkGroupInvocations = 128;
Int MaxShaderStorageBufferBindings = 8;
Int MaxTextureBufferSize = 65536;
Int MaxUniformBufferBindings = 24;
Int MaxUniformBlockSize = 16384;
Int MaxImageUnits = 8;
Int MaxCombinedImageUniforms = 8;
Int MaxComputeImageUniforms = 8;
Int MaxDrawBuffers = 8;
Int MaxColorAttachments = 8;
Int MaxClipDistances = 8;
Int MaxViewports = 16;
Int MaxViewportWidth = 16384;
Int MaxViewportHeight = 16384;
Float ViewportBoundsRangeMin = 0.0f;
Float ViewportBoundsRangeMax = 0.0f;
Int ViewportSubpixelBits = 0;
};
} // namespace MG_External
@@ -15,6 +15,29 @@ namespace MobileGL::MG_Util::BackendLoader {
PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2 = nullptr;
};
Int ResolveMaxRenderbufferSize(const VkPhysicalDeviceLimits& limits) {
return std::min<Int>(static_cast<Int>(limits.maxImageDimension2D),
std::min<Int>(static_cast<Int>(limits.maxFramebufferWidth),
static_cast<Int>(limits.maxFramebufferHeight)));
}
Int MaxSampleCountFromFlags(VkSampleCountFlags flags) {
if (flags & VK_SAMPLE_COUNT_64_BIT) return 64;
if (flags & VK_SAMPLE_COUNT_32_BIT) return 32;
if (flags & VK_SAMPLE_COUNT_16_BIT) return 16;
if (flags & VK_SAMPLE_COUNT_8_BIT) return 8;
if (flags & VK_SAMPLE_COUNT_4_BIT) return 4;
if (flags & VK_SAMPLE_COUNT_2_BIT) return 2;
return 1;
}
Int ResolveConservativeFramebufferSampleLimit(const VkPhysicalDeviceLimits& limits) {
const VkSampleCountFlags commonFlags = limits.framebufferColorSampleCounts &
limits.framebufferDepthSampleCounts &
limits.framebufferStencilSampleCounts;
return MaxSampleCountFromFlags(commonFlags);
}
VulkanDynamicFunctions LoadVulkanDynamicFunctions(VkInstance instance) {
VulkanDynamicFunctions loaded{};
if (instance == VK_NULL_HANDLE) {
@@ -83,6 +106,57 @@ namespace MobileGL::MG_Util::BackendLoader {
caps.DeviceName = p.deviceName;
caps.DriverVersionString = DecodeDriverVersion(p.driverVersion);
caps.UniformBufferOffsetAlignment = static_cast<int>(p.limits.minUniformBufferOffsetAlignment);
caps.AliasedLineWidthRangeMin = p.limits.lineWidthRange[0];
caps.AliasedLineWidthRangeMax = p.limits.lineWidthRange[1];
caps.SmoothLineWidthRangeMin = p.limits.lineWidthRange[0];
caps.SmoothLineWidthRangeMax = p.limits.lineWidthRange[1];
caps.SmoothLineWidthGranularity = p.limits.lineWidthGranularity;
caps.PointSizeRangeMin = p.limits.pointSizeRange[0];
caps.PointSizeRangeMax = p.limits.pointSizeRange[1];
caps.PointSizeGranularity = p.limits.pointSizeGranularity;
caps.Max3DTextureSize = static_cast<Int>(p.limits.maxImageDimension3D);
caps.MaxArrayTextureLayers = static_cast<Int>(p.limits.maxImageArrayLayers);
caps.MaxCubeMapTextureSize = static_cast<Int>(p.limits.maxImageDimensionCube);
caps.MaxFramebufferWidth = static_cast<Int>(p.limits.maxFramebufferWidth);
caps.MaxFramebufferHeight = static_cast<Int>(p.limits.maxFramebufferHeight);
caps.MaxFramebufferLayers = static_cast<Int>(p.limits.maxFramebufferLayers);
caps.MaxRenderbufferSize = ResolveMaxRenderbufferSize(p.limits);
caps.MaxTextureSize = static_cast<Int>(p.limits.maxImageDimension2D);
caps.MaxColorTextureSamples = MaxSampleCountFromFlags(p.limits.sampledImageColorSampleCounts);
caps.MaxDepthTextureSamples = MaxSampleCountFromFlags(p.limits.sampledImageDepthSampleCounts);
caps.MaxFramebufferSamples = ResolveConservativeFramebufferSampleLimit(p.limits);
caps.MaxIntegerSamples = MaxSampleCountFromFlags(p.limits.sampledImageIntegerSampleCounts);
caps.MaxSamples = caps.MaxFramebufferSamples;
caps.MaxSampleMaskWords = static_cast<Int>(p.limits.maxSampleMaskWords);
caps.MaxTextureImageUnits = static_cast<Int>(p.limits.maxPerStageDescriptorSampledImages);
caps.MaxVertexTextureImageUnits = static_cast<Int>(p.limits.maxPerStageDescriptorSampledImages);
caps.MaxComputeTextureImageUnits = static_cast<Int>(p.limits.maxPerStageDescriptorSampledImages);
caps.MaxCombinedTextureImageUnits = static_cast<Int>(p.limits.maxDescriptorSetSampledImages);
caps.MaxVertexAttribs = static_cast<Int>(p.limits.maxVertexInputAttributes);
caps.MaxComputeShaderStorageBlocks = static_cast<Int>(p.limits.maxPerStageDescriptorStorageBuffers);
caps.MaxCombinedShaderStorageBlocks = static_cast<Int>(p.limits.maxDescriptorSetStorageBuffers);
caps.MaxComputeUniformBlocks = static_cast<Int>(p.limits.maxPerStageDescriptorUniformBuffers);
caps.MaxComputeWorkGroupInvocations = static_cast<Int>(p.limits.maxComputeWorkGroupInvocations);
caps.MaxShaderStorageBufferBindings = static_cast<Int>(p.limits.maxDescriptorSetStorageBuffers);
caps.MaxTextureBufferSize = static_cast<Int>(p.limits.maxTexelBufferElements);
caps.MaxUniformBufferBindings = static_cast<Int>(p.limits.maxDescriptorSetUniformBuffers);
caps.MaxUniformBlockSize = static_cast<Int>(p.limits.maxUniformBufferRange);
caps.MaxImageUnits = static_cast<Int>(p.limits.maxPerStageDescriptorStorageImages);
caps.MaxCombinedImageUniforms = static_cast<Int>(p.limits.maxDescriptorSetStorageImages);
caps.MaxComputeImageUniforms = static_cast<Int>(p.limits.maxPerStageDescriptorStorageImages);
caps.MaxDrawBuffers = static_cast<Int>(p.limits.maxFragmentOutputAttachments);
caps.MaxColorAttachments = static_cast<Int>(p.limits.maxColorAttachments);
caps.MaxClipDistances = static_cast<Int>(p.limits.maxClipDistances);
caps.MaxViewports = static_cast<Int>(p.limits.maxViewports);
caps.MaxViewportWidth = static_cast<Int>(p.limits.maxViewportDimensions[0]);
caps.MaxViewportHeight = static_cast<Int>(p.limits.maxViewportDimensions[1]);
caps.ViewportBoundsRangeMin = p.limits.viewportBoundsRange[0];
caps.ViewportBoundsRangeMax = p.limits.viewportBoundsRange[1];
caps.ViewportSubpixelBits = static_cast<Int>(p.limits.viewportSubPixelBits);
VkPhysicalDeviceFeatures supportedFeatures{};
vkGetPhysicalDeviceFeatures(physicalDevice, &supportedFeatures);
caps.SupportsWideLines = supportedFeatures.wideLines == VK_TRUE;
return true;
}
@@ -93,5 +167,53 @@ namespace MobileGL::MG_Util::BackendLoader {
caps.DeviceName = properties.deviceName;
caps.DriverVersionString = DecodeDriverVersion(properties.driverVersion);
caps.UniformBufferOffsetAlignment = static_cast<int>(properties.limits.minUniformBufferOffsetAlignment);
caps.AliasedLineWidthRangeMin = properties.limits.lineWidthRange[0];
caps.AliasedLineWidthRangeMax = properties.limits.lineWidthRange[1];
caps.SmoothLineWidthRangeMin = properties.limits.lineWidthRange[0];
caps.SmoothLineWidthRangeMax = properties.limits.lineWidthRange[1];
caps.SmoothLineWidthGranularity = properties.limits.lineWidthGranularity;
caps.PointSizeRangeMin = properties.limits.pointSizeRange[0];
caps.PointSizeRangeMax = properties.limits.pointSizeRange[1];
caps.PointSizeGranularity = properties.limits.pointSizeGranularity;
caps.Max3DTextureSize = static_cast<Int>(properties.limits.maxImageDimension3D);
caps.MaxArrayTextureLayers = static_cast<Int>(properties.limits.maxImageArrayLayers);
caps.MaxCubeMapTextureSize = static_cast<Int>(properties.limits.maxImageDimensionCube);
caps.MaxFramebufferWidth = static_cast<Int>(properties.limits.maxFramebufferWidth);
caps.MaxFramebufferHeight = static_cast<Int>(properties.limits.maxFramebufferHeight);
caps.MaxFramebufferLayers = static_cast<Int>(properties.limits.maxFramebufferLayers);
caps.MaxRenderbufferSize = ResolveMaxRenderbufferSize(properties.limits);
caps.MaxTextureSize = static_cast<Int>(properties.limits.maxImageDimension2D);
caps.MaxColorTextureSamples = MaxSampleCountFromFlags(properties.limits.sampledImageColorSampleCounts);
caps.MaxDepthTextureSamples = MaxSampleCountFromFlags(properties.limits.sampledImageDepthSampleCounts);
caps.MaxFramebufferSamples = ResolveConservativeFramebufferSampleLimit(properties.limits);
caps.MaxIntegerSamples = MaxSampleCountFromFlags(properties.limits.sampledImageIntegerSampleCounts);
caps.MaxSamples = caps.MaxFramebufferSamples;
caps.MaxSampleMaskWords = static_cast<Int>(properties.limits.maxSampleMaskWords);
caps.MaxTextureImageUnits = static_cast<Int>(properties.limits.maxPerStageDescriptorSampledImages);
caps.MaxVertexTextureImageUnits = static_cast<Int>(properties.limits.maxPerStageDescriptorSampledImages);
caps.MaxComputeTextureImageUnits = static_cast<Int>(properties.limits.maxPerStageDescriptorSampledImages);
caps.MaxCombinedTextureImageUnits = static_cast<Int>(properties.limits.maxDescriptorSetSampledImages);
caps.MaxVertexAttribs = static_cast<Int>(properties.limits.maxVertexInputAttributes);
caps.MaxComputeShaderStorageBlocks = static_cast<Int>(properties.limits.maxPerStageDescriptorStorageBuffers);
caps.MaxCombinedShaderStorageBlocks = static_cast<Int>(properties.limits.maxDescriptorSetStorageBuffers);
caps.MaxComputeUniformBlocks = static_cast<Int>(properties.limits.maxPerStageDescriptorUniformBuffers);
caps.MaxComputeWorkGroupInvocations = static_cast<Int>(properties.limits.maxComputeWorkGroupInvocations);
caps.MaxShaderStorageBufferBindings = static_cast<Int>(properties.limits.maxDescriptorSetStorageBuffers);
caps.MaxTextureBufferSize = static_cast<Int>(properties.limits.maxTexelBufferElements);
caps.MaxUniformBufferBindings = static_cast<Int>(properties.limits.maxDescriptorSetUniformBuffers);
caps.MaxUniformBlockSize = static_cast<Int>(properties.limits.maxUniformBufferRange);
caps.MaxImageUnits = static_cast<Int>(properties.limits.maxPerStageDescriptorStorageImages);
caps.MaxCombinedImageUniforms = static_cast<Int>(properties.limits.maxDescriptorSetStorageImages);
caps.MaxComputeImageUniforms = static_cast<Int>(properties.limits.maxPerStageDescriptorStorageImages);
caps.MaxDrawBuffers = static_cast<Int>(properties.limits.maxFragmentOutputAttachments);
caps.MaxColorAttachments = static_cast<Int>(properties.limits.maxColorAttachments);
caps.MaxClipDistances = static_cast<Int>(properties.limits.maxClipDistances);
caps.MaxViewports = static_cast<Int>(properties.limits.maxViewports);
caps.MaxViewportWidth = static_cast<Int>(properties.limits.maxViewportDimensions[0]);
caps.MaxViewportHeight = static_cast<Int>(properties.limits.maxViewportDimensions[1]);
caps.ViewportBoundsRangeMin = properties.limits.viewportBoundsRange[0];
caps.ViewportBoundsRangeMax = properties.limits.viewportBoundsRange[1];
caps.ViewportSubpixelBits = static_cast<Int>(properties.limits.viewportSubPixelBits);
caps.SupportsWideLines = false;
}
} // namespace MobileGL::MG_Util::BackendLoader
@@ -16,6 +16,54 @@ namespace MobileGL {
String DeviceName;
String DriverVersionString;
Int UniformBufferOffsetAlignment = 256;
Float AliasedLineWidthRangeMin = 1.0f;
Float AliasedLineWidthRangeMax = 1.0f;
Float SmoothLineWidthRangeMin = 1.0f;
Float SmoothLineWidthRangeMax = 1.0f;
Float SmoothLineWidthGranularity = 1.0f;
Float PointSizeRangeMin = 1.0f;
Float PointSizeRangeMax = 1.0f;
Float PointSizeGranularity = 1.0f;
Int Max3DTextureSize = 16384;
Int MaxArrayTextureLayers = 2048;
Int MaxCubeMapTextureSize = 16384;
Int MaxFramebufferWidth = 16384;
Int MaxFramebufferHeight = 16384;
Int MaxFramebufferLayers = 2048;
Int MaxRenderbufferSize = 16384;
Int MaxTextureSize = 16384;
Int MaxColorTextureSamples = 1;
Int MaxDepthTextureSamples = 1;
Int MaxFramebufferSamples = 1;
Int MaxIntegerSamples = 1;
Int MaxSamples = 1;
Int MaxSampleMaskWords = 1;
Int MaxTextureImageUnits = 32;
Int MaxVertexTextureImageUnits = 32;
Int MaxComputeTextureImageUnits = 32;
Int MaxCombinedTextureImageUnits = 192;
Int MaxVertexAttribs = 16;
Int MaxComputeShaderStorageBlocks = 8;
Int MaxCombinedShaderStorageBlocks = 32;
Int MaxComputeUniformBlocks = 12;
Int MaxComputeWorkGroupInvocations = 128;
Int MaxShaderStorageBufferBindings = 8;
Int MaxTextureBufferSize = 65536;
Int MaxUniformBufferBindings = 24;
Int MaxUniformBlockSize = 16384;
Int MaxImageUnits = 8;
Int MaxCombinedImageUniforms = 8;
Int MaxComputeImageUniforms = 8;
Int MaxDrawBuffers = 8;
Int MaxColorAttachments = 8;
Int MaxClipDistances = 8;
Int MaxViewports = 16;
Int MaxViewportWidth = 16384;
Int MaxViewportHeight = 16384;
Float ViewportBoundsRangeMin = 0.0f;
Float ViewportBoundsRangeMax = 0.0f;
Int ViewportSubpixelBits = 0;
Bool SupportsWideLines = false;
};
} // namespace MG_External
namespace MG_Util::BackendLoader {
@@ -24,6 +24,8 @@ namespace MobileGL {
return DataType::Int32;
case GL_UNSIGNED_INT:
return DataType::Uint32;
case GL_FIXED:
return DataType::Fixed32;
case GL_HALF_FLOAT:
return DataType::Float16;
case GL_FLOAT:
@@ -35,4 +37,4 @@ namespace MobileGL {
}
}
} // namespace MG_Util
} // namespace MobileGL
} // namespace MobileGL
@@ -62,6 +62,45 @@ namespace MobileGL {
}
}
LogicOperation ConvertGLEnumToLogicOperation(GLenum v) {
switch (v) {
case GL_CLEAR:
return LogicOperation::Clear;
case GL_AND:
return LogicOperation::And;
case GL_AND_REVERSE:
return LogicOperation::AndReverse;
case GL_COPY:
return LogicOperation::Copy;
case GL_AND_INVERTED:
return LogicOperation::AndInverted;
case GL_NOOP:
return LogicOperation::Noop;
case GL_XOR:
return LogicOperation::Xor;
case GL_OR:
return LogicOperation::Or;
case GL_NOR:
return LogicOperation::Nor;
case GL_EQUIV:
return LogicOperation::Equiv;
case GL_INVERT:
return LogicOperation::Invert;
case GL_OR_REVERSE:
return LogicOperation::OrReverse;
case GL_COPY_INVERTED:
return LogicOperation::CopyInverted;
case GL_OR_INVERTED:
return LogicOperation::OrInverted;
case GL_NAND:
return LogicOperation::Nand;
case GL_SET:
return LogicOperation::Set;
default:
return LogicOperation::Unknown;
}
}
DepthTestFunc ConvertGLEnumToDepthTestFunc(GLenum v) {
switch (v) {
case GL_NEVER:
@@ -85,6 +124,29 @@ namespace MobileGL {
}
}
StencilOperation ConvertGLEnumToStencilOperation(GLenum v) {
switch (v) {
case GL_KEEP:
return StencilOperation::Keep;
case GL_ZERO:
return StencilOperation::Zero;
case GL_REPLACE:
return StencilOperation::Replace;
case GL_INCR:
return StencilOperation::IncrementClamp;
case GL_DECR:
return StencilOperation::DecrementClamp;
case GL_INVERT:
return StencilOperation::Invert;
case GL_INCR_WRAP:
return StencilOperation::IncrementWrap;
case GL_DECR_WRAP:
return StencilOperation::DecrementWrap;
default:
return StencilOperation::Unknown;
}
}
PixelStoreParam ConvertGLEnumToPixelStoreParam(GLenum v) {
switch (v) {
case GL_PACK_ALIGNMENT:
@@ -14,7 +14,9 @@ namespace MobileGL {
namespace MG_Util {
BlendFactor ConvertGLEnumToBlendFactor(GLenum value);
BlendEquation ConvertGLEnumToBlendEquation(GLenum value);
LogicOperation ConvertGLEnumToLogicOperation(GLenum value);
DepthTestFunc ConvertGLEnumToDepthTestFunc(GLenum value);
StencilOperation ConvertGLEnumToStencilOperation(GLenum value);
PixelStoreParam ConvertGLEnumToPixelStoreParam(GLenum value);
CullFaceMode ConvertGLEnumToCullFaceMode(GLenum value);
FrontFaceMode ConvertGLEnumToFrontFaceMode(GLenum value);
@@ -14,12 +14,16 @@ namespace MobileGL {
TextureTarget ConvertGLEnumToTextureTarget(GLenum target) {
switch (target) {
case GL_TEXTURE_1D:
case GL_PROXY_TEXTURE_1D:
return TextureTarget::Texture1D;
case GL_TEXTURE_2D:
case GL_PROXY_TEXTURE_2D:
return TextureTarget::Texture2D;
case GL_TEXTURE_3D:
case GL_PROXY_TEXTURE_3D:
return TextureTarget::Texture3D;
case GL_TEXTURE_CUBE_MAP:
case GL_PROXY_TEXTURE_CUBE_MAP:
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
@@ -28,18 +32,24 @@ namespace MobileGL {
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
return TextureTarget::TextureCubeMap;
case GL_TEXTURE_2D_ARRAY:
case GL_PROXY_TEXTURE_2D_ARRAY:
return TextureTarget::Texture2DArray;
case GL_TEXTURE_2D_MULTISAMPLE:
case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
return TextureTarget::Texture2DMultisample;
case GL_TEXTURE_CUBE_MAP_ARRAY:
case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
return TextureTarget::TextureCubeMapArray;
case GL_TEXTURE_BUFFER:
return TextureTarget::TextureBuffer;
case GL_TEXTURE_1D_ARRAY:
case GL_PROXY_TEXTURE_1D_ARRAY:
return TextureTarget::Texture1DArray;
case GL_TEXTURE_RECTANGLE:
case GL_PROXY_TEXTURE_RECTANGLE:
return TextureTarget::TextureRectangle;
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
return TextureTarget::Texture2DMultisampleArray;
default:
return TextureTarget::Unknown;
@@ -24,6 +24,8 @@ namespace MobileGL {
return GL_INT;
case DataType::Uint32:
return GL_UNSIGNED_INT;
case DataType::Fixed32:
return GL_FIXED;
case DataType::Float16:
return GL_HALF_FLOAT;
case DataType::Float32:
@@ -35,4 +37,4 @@ namespace MobileGL {
}
}
} // namespace MG_Util
} // namespace MobileGL
} // namespace MobileGL
@@ -16,8 +16,9 @@ namespace MobileGL {
return GL_DRAW_FRAMEBUFFER;
case FramebufferTarget::Read:
return GL_READ_FRAMEBUFFER;
case FramebufferTarget::Unknown:
default:
return GL_DRAW_FRAMEBUFFER;
return GL_UNKNOWN_MGL;
}
}
@@ -29,6 +30,8 @@ namespace MobileGL {
}
switch (type) {
case FramebufferAttachmentType::None:
return GL_NONE;
case FramebufferAttachmentType::Depth:
return GL_DEPTH_ATTACHMENT;
case FramebufferAttachmentType::Stencil:
@@ -41,8 +44,9 @@ namespace MobileGL {
return GL_BACK_LEFT;
case FramebufferAttachmentType::BackRight:
return GL_BACK_RIGHT;
case FramebufferAttachmentType::Unknown:
default:
return GL_NONE;
return GL_UNKNOWN_MGL;
}
}
@@ -50,10 +54,11 @@ namespace MobileGL {
switch (target) {
case RenderbufferTarget::Renderbuffer:
return GL_RENDERBUFFER;
case RenderbufferTarget::Unknown:
default:
return GL_RENDERBUFFER;
return GL_UNKNOWN_MGL;
}
}
} // namespace MG_Util
} // namespace MobileGL
} // namespace MobileGL
@@ -63,6 +63,45 @@ namespace MobileGL {
}
}
GLenum ConvertLogicOperationToGLEnum(LogicOperation v) {
switch (v) {
case LogicOperation::Clear:
return GL_CLEAR;
case LogicOperation::And:
return GL_AND;
case LogicOperation::AndReverse:
return GL_AND_REVERSE;
case LogicOperation::Copy:
return GL_COPY;
case LogicOperation::AndInverted:
return GL_AND_INVERTED;
case LogicOperation::Noop:
return GL_NOOP;
case LogicOperation::Xor:
return GL_XOR;
case LogicOperation::Or:
return GL_OR;
case LogicOperation::Nor:
return GL_NOR;
case LogicOperation::Equiv:
return GL_EQUIV;
case LogicOperation::Invert:
return GL_INVERT;
case LogicOperation::OrReverse:
return GL_OR_REVERSE;
case LogicOperation::CopyInverted:
return GL_COPY_INVERTED;
case LogicOperation::OrInverted:
return GL_OR_INVERTED;
case LogicOperation::Nand:
return GL_NAND;
case LogicOperation::Set:
return GL_SET;
default:
return GL_UNKNOWN_MGL;
}
}
GLenum ConvertDepthTestFuncToGLEnum(DepthTestFunc v) {
switch (v) {
case DepthTestFunc::Never:
@@ -86,6 +125,29 @@ namespace MobileGL {
}
}
GLenum ConvertStencilOperationToGLEnum(StencilOperation v) {
switch (v) {
case StencilOperation::Keep:
return GL_KEEP;
case StencilOperation::Zero:
return GL_ZERO;
case StencilOperation::Replace:
return GL_REPLACE;
case StencilOperation::IncrementClamp:
return GL_INCR;
case StencilOperation::DecrementClamp:
return GL_DECR;
case StencilOperation::Invert:
return GL_INVERT;
case StencilOperation::IncrementWrap:
return GL_INCR_WRAP;
case StencilOperation::DecrementWrap:
return GL_DECR_WRAP;
default:
return GL_UNKNOWN_MGL;
}
}
GLenum ConvertPixelStoreParamToGLEnum(PixelStoreParam v) {
switch (v) {
case PixelStoreParam::PackAlignment:
@@ -14,7 +14,9 @@ namespace MobileGL {
namespace MG_Util {
GLenum ConvertBlendFactorToGLEnum(BlendFactor value);
GLenum ConvertBlendEquationToGLEnum(BlendEquation value);
GLenum ConvertLogicOperationToGLEnum(LogicOperation value);
GLenum ConvertDepthTestFuncToGLEnum(DepthTestFunc value);
GLenum ConvertStencilOperationToGLEnum(StencilOperation value);
GLenum ConvertPixelStoreParamToGLEnum(PixelStoreParam value);
GLenum ConvertCullFaceModeToGLEnum(CullFaceMode value);
GLenum ConvertFrontFaceModeToGLEnum(FrontFaceMode value);
@@ -110,6 +110,8 @@ namespace MobileGL {
return GL_RGB10;
case TextureInternalFormat::RGB12:
return GL_RGB12;
case TextureInternalFormat::RGB16:
return GL_RGB16;
case TextureInternalFormat::RGB16Snorm:
return GL_RGB16_SNORM;
case TextureInternalFormat::RGBA2:
@@ -267,6 +269,8 @@ namespace MobileGL {
return GL_UNSIGNED_SHORT_5_5_5_1;
case TexturePixelDataType::UnsignedShort1555Rev:
return GL_UNSIGNED_SHORT_1_5_5_5_REV;
case TexturePixelDataType::UnsignedInt8888:
return GL_UNSIGNED_INT_8_8_8_8;
case TexturePixelDataType::UnsignedInt8888Rev:
return GL_UNSIGNED_INT_8_8_8_8_REV;
case TexturePixelDataType::UnsignedInt1010102:
@@ -72,6 +72,10 @@ namespace MobileGL {
}
String ConvertBufferMappingAccessToString(Flags<BufferMappingAccessBit> access) {
if (access == BufferMappingAccessBit::Null) {
return "[]";
}
String result = "[";
if (access & BufferMappingAccessBit::Read) result += "Read, ";
if (access & BufferMappingAccessBit::Write) result += "Write, ";
@@ -84,7 +88,7 @@ namespace MobileGL {
result.pop_back();
result.pop_back();
result += "]";
return result.empty() ? "[]" : result;
return result;
}
} // namespace MG_Util
} // namespace MobileGL
} // namespace MobileGL
@@ -29,6 +29,16 @@ namespace MobileGL {
}
switch (attachment) {
case FramebufferAttachmentType::None:
return "None";
case FramebufferAttachmentType::FrontLeft:
return "FrontLeft";
case FramebufferAttachmentType::FrontRight:
return "FrontRight";
case FramebufferAttachmentType::BackLeft:
return "BackLeft";
case FramebufferAttachmentType::BackRight:
return "BackRight";
case FramebufferAttachmentType::Depth:
return "Depth";
case FramebufferAttachmentType::Stencil:
@@ -49,4 +59,4 @@ namespace MobileGL {
}
}
} // namespace MG_Util
} // namespace MobileGL
} // namespace MobileGL
@@ -45,6 +45,45 @@ namespace MobileGL {
}
}
String ConvertLogicOperationToString(LogicOperation v) {
switch (v) {
case LogicOperation::Clear:
return "Clear";
case LogicOperation::And:
return "And";
case LogicOperation::AndReverse:
return "AndReverse";
case LogicOperation::Copy:
return "Copy";
case LogicOperation::AndInverted:
return "AndInverted";
case LogicOperation::Noop:
return "Noop";
case LogicOperation::Xor:
return "Xor";
case LogicOperation::Or:
return "Or";
case LogicOperation::Nor:
return "Nor";
case LogicOperation::Equiv:
return "Equiv";
case LogicOperation::Invert:
return "Invert";
case LogicOperation::OrReverse:
return "OrReverse";
case LogicOperation::CopyInverted:
return "CopyInverted";
case LogicOperation::OrInverted:
return "OrInverted";
case LogicOperation::Nand:
return "Nand";
case LogicOperation::Set:
return "Set";
default:
return "Unknown";
}
}
String ConvertDepthTestFuncToString(DepthTestFunc v) {
switch (v) {
case DepthTestFunc::Never:
@@ -68,6 +107,29 @@ namespace MobileGL {
}
}
String ConvertStencilOperationToString(StencilOperation v) {
switch (v) {
case StencilOperation::Keep:
return "Keep";
case StencilOperation::Zero:
return "Zero";
case StencilOperation::Replace:
return "Replace";
case StencilOperation::IncrementClamp:
return "IncrementClamp";
case StencilOperation::DecrementClamp:
return "DecrementClamp";
case StencilOperation::Invert:
return "Invert";
case StencilOperation::IncrementWrap:
return "IncrementWrap";
case StencilOperation::DecrementWrap:
return "DecrementWrap";
default:
return "Unknown";
}
}
String ConvertPixelStoreParamToString(PixelStoreParam v) {
switch (v) {
case PixelStoreParam::PackAlignment:
@@ -13,7 +13,9 @@
namespace MobileGL {
namespace MG_Util {
String ConvertBlendFactorToString(BlendFactor value);
String ConvertLogicOperationToString(LogicOperation value);
String ConvertDepthTestFuncToString(DepthTestFunc value);
String ConvertStencilOperationToString(StencilOperation value);
String ConvertPixelStoreParamToString(PixelStoreParam value);
String ConvertCullFaceModeToString(CullFaceMode value);
String ConvertFrontFaceModeToString(FrontFaceMode value);
@@ -110,6 +110,8 @@ namespace MobileGL {
return "RGB10";
case TextureInternalFormat::RGB12:
return "RGB12";
case TextureInternalFormat::RGB16:
return "RGB16";
case TextureInternalFormat::RGB16Snorm:
return "RGB16Snorm";
case TextureInternalFormat::RGBA2:
@@ -47,6 +47,45 @@ namespace MobileGL {
}
}
VkLogicOp ConvertLogicOperationToVkEnum(LogicOperation v) {
switch (v) {
case LogicOperation::Clear:
return VK_LOGIC_OP_CLEAR;
case LogicOperation::And:
return VK_LOGIC_OP_AND;
case LogicOperation::AndReverse:
return VK_LOGIC_OP_AND_REVERSE;
case LogicOperation::Copy:
return VK_LOGIC_OP_COPY;
case LogicOperation::AndInverted:
return VK_LOGIC_OP_AND_INVERTED;
case LogicOperation::Noop:
return VK_LOGIC_OP_NO_OP;
case LogicOperation::Xor:
return VK_LOGIC_OP_XOR;
case LogicOperation::Or:
return VK_LOGIC_OP_OR;
case LogicOperation::Nor:
return VK_LOGIC_OP_NOR;
case LogicOperation::Equiv:
return VK_LOGIC_OP_EQUIVALENT;
case LogicOperation::Invert:
return VK_LOGIC_OP_INVERT;
case LogicOperation::OrReverse:
return VK_LOGIC_OP_OR_REVERSE;
case LogicOperation::CopyInverted:
return VK_LOGIC_OP_COPY_INVERTED;
case LogicOperation::OrInverted:
return VK_LOGIC_OP_OR_INVERTED;
case LogicOperation::Nand:
return VK_LOGIC_OP_NAND;
case LogicOperation::Set:
return VK_LOGIC_OP_SET;
default:
return VK_LOGIC_OP_COPY;
}
}
VkCompareOp ConvertDepthTestFuncToVkEnum(DepthTestFunc v) {
switch (v) {
case DepthTestFunc::Never:
@@ -69,6 +108,29 @@ namespace MobileGL {
}
}
VkStencilOp ConvertStencilOperationToVkEnum(StencilOperation v) {
switch (v) {
case StencilOperation::Keep:
return VK_STENCIL_OP_KEEP;
case StencilOperation::Zero:
return VK_STENCIL_OP_ZERO;
case StencilOperation::Replace:
return VK_STENCIL_OP_REPLACE;
case StencilOperation::IncrementClamp:
return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
case StencilOperation::DecrementClamp:
return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
case StencilOperation::Invert:
return VK_STENCIL_OP_INVERT;
case StencilOperation::IncrementWrap:
return VK_STENCIL_OP_INCREMENT_AND_WRAP;
case StencilOperation::DecrementWrap:
return VK_STENCIL_OP_DECREMENT_AND_WRAP;
default:
return VK_STENCIL_OP_KEEP;
}
}
VkBlendFactor ConvertBlendFactorToVkEnum(BlendFactor v) {
switch (v) {
case BlendFactor::Zero:
@@ -14,7 +14,9 @@ namespace MobileGL {
namespace MG_Util {
VkPrimitiveTopology ConvertPrimitiveModeToVkEnum(GLenum mode);
VkCullModeFlags ConvertCullFaceModeToVkEnum(CullFaceMode value, Bool invertClockwise = false);
VkLogicOp ConvertLogicOperationToVkEnum(LogicOperation value);
VkCompareOp ConvertDepthTestFuncToVkEnum(DepthTestFunc value);
VkStencilOp ConvertStencilOperationToVkEnum(StencilOperation value);
VkBlendFactor ConvertBlendFactorToVkEnum(BlendFactor value);
VkBlendOp ConvertBlendEquationToVkEnum(BlendEquation value);
} // namespace MG_Util
+3 -1
View File
@@ -95,11 +95,13 @@ namespace MobileGL {
va_list args;
va_start(args, fmt);
int n = std::vsnprintf(buffer, sizeof(buffer), fmt, args);
const SizeT messageLength =
(n < 0) ? 0 : std::min(static_cast<SizeT>(n), sizeof(buffer) - static_cast<SizeT>(1));
std::string out = header +
#if MOBILEGL_LOG_ENABLE_STACKTRACE
padding +
#endif
std::string(buffer, n) + "\n";
std::string(buffer, messageLength) + "\n";
#if MOBILEGL_LOG_ENABLE_CONSOLE
std::fwrite(out.c_str(), 1, out.size(), stdout);
+25 -2
View File
@@ -43,6 +43,10 @@ namespace MobileGL {
case TextureInternalFormat::DepthComponent24:
return 3;
case TextureInternalFormat::RGB10:
case TextureInternalFormat::RGB12:
case TextureInternalFormat::RGB16:
case TextureInternalFormat::RGB16Snorm:
case TextureInternalFormat::RGBA2:
case TextureInternalFormat::RGBA4:
case TextureInternalFormat::RGB5A1:
@@ -54,6 +58,8 @@ namespace MobileGL {
case TextureInternalFormat::RGB10A2:
case TextureInternalFormat::RGB10A2UI:
case TextureInternalFormat::R32F:
case TextureInternalFormat::R32I:
case TextureInternalFormat::R32UI:
case TextureInternalFormat::DepthComponent:
case TextureInternalFormat::DepthComponent32:
case TextureInternalFormat::DepthComponent32F:
@@ -179,6 +185,7 @@ namespace MobileGL {
case TextureInternalFormat::RGB10:
case TextureInternalFormat::RGB12:
case TextureInternalFormat::RGB16:
case TextureInternalFormat::RGB16Snorm:
case TextureInternalFormat::SRGB8:
case TextureInternalFormat::RGB8I:
case TextureInternalFormat::RGB8UI:
@@ -236,7 +243,6 @@ namespace MobileGL {
case TexturePixelDataType::UnsignedInt248:
case TexturePixelDataType::Float32UnsignedInt248Rev:
return 4;
return 4;
default:
return 0;
}
@@ -339,6 +345,22 @@ namespace MobileGL {
s.Green = 8;
s.Blue = 8;
break;
case TextureInternalFormat::RGB10:
s.Red = 10;
s.Green = 10;
s.Blue = 10;
break;
case TextureInternalFormat::RGB12:
s.Red = 12;
s.Green = 12;
s.Blue = 12;
break;
case TextureInternalFormat::RGB16:
case TextureInternalFormat::RGB16Snorm:
s.Red = 16;
s.Green = 16;
s.Blue = 16;
break;
case TextureInternalFormat::R3G3B2:
s.Red = 3;
@@ -370,7 +392,6 @@ namespace MobileGL {
case TextureInternalFormat::RGBA8UI:
case TextureInternalFormat::SRGB8Alpha8:
case TextureInternalFormat::RGBA:
break;
s.Red = 8;
s.Green = 8;
s.Blue = 8;
@@ -385,6 +406,8 @@ namespace MobileGL {
break;
case TextureInternalFormat::R32F:
case TextureInternalFormat::R32I:
case TextureInternalFormat::R32UI:
s.Red = 32;
break;
case TextureInternalFormat::RG32F:
@@ -200,6 +200,10 @@ namespace MobileGL {
size_t commentStartPos = source.find("/*");
while (commentStartPos != String::npos) {
size_t commentEndPos = source.find("*/", commentStartPos);
if (commentEndPos == String::npos) {
source.erase(commentStartPos);
break;
}
// + length of "*/"
source = source.replace(commentStartPos, commentEndPos - commentStartPos + 2, "");
commentStartPos = source.find("/*", commentStartPos);
@@ -120,11 +120,27 @@ namespace MobileGL {
less_operands.push_back({SPV_OPERAND_TYPE_ID, {abs_inst->result_id()}});
less_operands.push_back({SPV_OPERAND_TYPE_ID, {eps_id}});
bool isEqualOp =
(inst.opcode() == spv::Op::OpFOrdEqual || inst.opcode() == spv::Op::OpFUnordEqual);
spv::Op replacementOp = spv::Op::OpNop;
switch (inst.opcode()) {
case spv::Op::OpFOrdEqual:
replacementOp = spv::Op::OpFOrdLessThan;
break;
case spv::Op::OpFUnordEqual:
replacementOp = spv::Op::OpFUnordLessThan;
break;
case spv::Op::OpFOrdNotEqual:
replacementOp = spv::Op::OpFOrdGreaterThanEqual;
break;
case spv::Op::OpFUnordNotEqual:
replacementOp = spv::Op::OpFUnordGreaterThanEqual;
break;
default:
MOBILEGL_ASSERT(false, "Unexpected float compare opcode: %d",
static_cast<int>(inst.opcode()));
break;
}
Instruction* less_than_inst = builder.AddInstruction(MakeUnique<Instruction>(
context(), isEqualOp ? spv::Op::OpFOrdLessThan : spv::Op::OpFOrdGreaterThanEqual,
bool_type_id, context()->TakeNextId(), less_operands));
context(), replacementOp, bool_type_id, context()->TakeNextId(), less_operands));
// 5. Replaces all uses of old insn with new one
context()->ReplaceAllUsesWith(inst.result_id(), less_than_inst->result_id());
@@ -149,4 +165,4 @@ namespace MobileGL {
}
} // namespace ShaderTranspiler
} // namespace MG_Util
} // namespace MobileGL
} // namespace MobileGL
@@ -70,7 +70,7 @@ namespace MobileGL {
class SpvcSession {
public:
SpvcSession() {}
SpvcSession() = default;
explicit SpvcSession(const Vector<unsigned int>& spirv,
Flags<SessionUsageBit> usage);
@@ -97,7 +97,7 @@ namespace MobileGL {
spvc_result ParseMetaData();
private:
Flags<SessionUsageBit> usage;
Flags<SessionUsageBit> usage{};
// SPIRV-Cross state (used when Transpile flag is set)
spvc_context context = nullptr;
@@ -114,4 +114,4 @@ namespace MobileGL {
};
} // namespace ShaderTranspiler
} // namespace MG_Util
} // namespace MobileGL
} // namespace MobileGL
@@ -154,8 +154,8 @@ namespace MobileGL::MG_Util::PixelStoreProcessor {
MGLOG_D("%s: Swizzle (BGRA)", __func__);
// MGLOG_D("%s: pixel0 before = %x", __func__, *((Uint32*)layerDst));
ProcessColorSwizzle(layerDst, static_cast<SizeT>(copyWidth),
{TextureSwizzleParam::Green, TextureSwizzleParam::Blue,
TextureSwizzleParam::Alpha, TextureSwizzleParam::Red});
{TextureSwizzleParam::Blue, TextureSwizzleParam::Green,
TextureSwizzleParam::Red, TextureSwizzleParam::Alpha});
// MGLOG_D("%s: pixel0 after = %x", __func__, *((Uint32*)layerDst));
}
// else
@@ -157,6 +157,9 @@ namespace MobileGL::MG_Util::TextureFormatProcessor {
case GL_SRGB8:
*outFormat = GL_RGB;
break;
case GL_SRGB8_ALPHA8:
*outFormat = GL_RGBA;
break;
// Color sized other
case GL_RGB9_E5:
@@ -178,6 +181,7 @@ namespace MobileGL::MG_Util::TextureFormatProcessor {
break;
// Depth Stencil
case GL_DEPTH24_STENCIL8:
case GL_DEPTH32F_STENCIL8:
case GL_DEPTH_STENCIL:
*outFormat = GL_DEPTH_STENCIL;
@@ -298,6 +302,9 @@ namespace MobileGL::MG_Util::TextureFormatProcessor {
case GL_SRGB8:
*outType = GL_UNSIGNED_BYTE;
break;
case GL_SRGB8_ALPHA8:
*outType = GL_UNSIGNED_BYTE;
break;
// Color sized other
case GL_RGB9_E5:
@@ -331,6 +338,9 @@ namespace MobileGL::MG_Util::TextureFormatProcessor {
break;
// Depth Stencil
case GL_DEPTH24_STENCIL8:
*outType = GL_UNSIGNED_INT_24_8;
break;
case GL_DEPTH32F_STENCIL8:
case GL_DEPTH_STENCIL:
*outType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
@@ -345,4 +355,4 @@ namespace MobileGL::MG_Util::TextureFormatProcessor {
}
}
}
} // namespace MobileGL::MG_Util::TextureFormatProcessor
} // namespace MobileGL::MG_Util::TextureFormatProcessor
+1 -1
View File
@@ -115,7 +115,7 @@ namespace MobileGL {
// represents a range of [start, end)
struct Range1D {
SizeT start = 0;
SizeT end = ~0u;
SizeT end = ~SizeT(0);
void Update(SizeT newStart, SizeT newEnd) {
MOBILEGL_ASSERT(newStart <= newEnd, "Range1D::Update: newStart (%zu) > newEnd (%zu)", newStart, newEnd);
+826
View File
File diff suppressed because one or more lines are too long