mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[Fix, Test] (MG_Backend, MG_Impl, MG_State): advertise the uniform-block and stencil-texturing strings a 4.0 context hides behind, forward DEPTH_STENCIL_TEXTURE_MODE to both backends, and stop a reserved transform feedback name passing for an object
This commit is contained in:
@@ -940,6 +940,17 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// picks a whole different shader for draw_buffers without
|
// picks a whole different shader for draw_buffers without
|
||||||
// explicit_attrib_location. DirectVulkan advertises both.
|
// explicit_attrib_location. DirectVulkan advertises both.
|
||||||
E_GL_ARB_explicit_attrib_location, E_GL_ARB_texture_multisample, E_GL_ARB_shader_image_size,
|
E_GL_ARB_explicit_attrib_location, E_GL_ARB_texture_multisample, E_GL_ARB_shader_image_size,
|
||||||
|
// Core since GL 3.1 and implemented for every version advertised here. The string
|
||||||
|
// matters because applications gate the ENTRY POINTS on it rather than on the
|
||||||
|
// version: a caller that finds the extension missing never resolves
|
||||||
|
// glGetUniformBlockIndex / glUniformBlockBinding, and one that then uses uniform
|
||||||
|
// blocks anyway calls through a null pointer.
|
||||||
|
E_GL_ARB_uniform_buffer_object,
|
||||||
|
// Sampling the stencil aspect through DEPTH_STENCIL_TEXTURE_MODE. Core from 4.3,
|
||||||
|
// so on a 4.0 context the string is the only way to reach it. The host ES driver
|
||||||
|
// has had the same texture parameter since ES 3.1, which every device MobileGL
|
||||||
|
// runs on provides.
|
||||||
|
E_GL_ARB_stencil_texturing,
|
||||||
// Advertised with GL_NUM_PROGRAM_BINARY_FORMATS = 0, which the
|
// Advertised with GL_NUM_PROGRAM_BINARY_FORMATS = 0, which the
|
||||||
// extension explicitly permits. It is also the only thing that
|
// extension explicitly permits. It is also the only thing that
|
||||||
// exposes glProgramParameteri before GL 4.1.
|
// exposes glProgramParameteri before GL 4.1.
|
||||||
|
|||||||
@@ -3315,6 +3315,29 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GL_DEPTH_STENCIL_TEXTURE_MODE (GL_ARB_stencil_texturing / ES 3.1 core): which aspect
|
||||||
|
// of a packed depth/stencil image a sampler reads. Until this was forwarded the
|
||||||
|
// frontend kept the mode as a pure shadow - glGetTexParameter answered it, sampling
|
||||||
|
// ignored it - so a usampler2D bound to a D24S8 texture in STENCIL_INDEX mode read the
|
||||||
|
// depth aspect. Texture state rather than sampler state, so multisample targets take
|
||||||
|
// it too (ES 3.1 8.10 lists it among the three pnames they accept). It is only sent
|
||||||
|
// when it has moved, which for the overwhelming majority of textures is never.
|
||||||
|
const Bool supportsStencilTextureMode =
|
||||||
|
g_GLESCapabilities.GLESVersion.Major > 3 ||
|
||||||
|
(g_GLESCapabilities.GLESVersion.Major == 3 && g_GLESCapabilities.GLESVersion.Minor >= 1);
|
||||||
|
if (supportsStencilTextureMode) {
|
||||||
|
const GLenum depthStencilTextureMode = stateTextureObject->GetDepthStencilTextureMode();
|
||||||
|
if (m_cacheDepthStencilTextureMode != depthStencilTextureMode) {
|
||||||
|
g_GLESFuncs.glTexParameteri(target, GL_DEPTH_STENCIL_TEXTURE_MODE,
|
||||||
|
static_cast<GLint>(depthStencilTextureMode));
|
||||||
|
m_cacheDepthStencilTextureMode = depthStencilTextureMode;
|
||||||
|
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__](GLenum err) {
|
||||||
|
MGLOG_D("%s(%s:%d) ES error %s", func, file, line,
|
||||||
|
MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivateTextureUnit(Uint unit) {
|
void ActivateTextureUnit(Uint unit) {
|
||||||
|
|||||||
@@ -699,6 +699,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
FloatVec4 m_cacheBorderColor = {0.0f, 0.0f, 0.0f, 0.0f};
|
FloatVec4 m_cacheBorderColor = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
Vec4<TextureSwizzleParam> m_cacheSwizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green,
|
Vec4<TextureSwizzleParam> m_cacheSwizzleParams = {TextureSwizzleParam::Red, TextureSwizzleParam::Green,
|
||||||
TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha};
|
TextureSwizzleParam::Blue, TextureSwizzleParam::Alpha};
|
||||||
|
// GL_DEPTH_STENCIL_TEXTURE_MODE. GL_DEPTH_COMPONENT is the GL and ES default, so a
|
||||||
|
// texture that never asks for the stencil aspect never emits the call. The
|
||||||
|
// depth/stencil readback and replicate-blit emulations also write this parameter
|
||||||
|
// raw, but only ever on their own scratch textures (never on an application
|
||||||
|
// texture), so they cannot desynchronise this cache.
|
||||||
|
GLenum m_cacheDepthStencilTextureMode = GL_DEPTH_COMPONENT;
|
||||||
Uint16 m_syncedSamplerVersion = 0;
|
Uint16 m_syncedSamplerVersion = 0;
|
||||||
Uint16 m_syncedTextureParamsVersion = 0;
|
Uint16 m_syncedTextureParamsVersion = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -517,6 +517,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
E_GL_ARB_gpu_shader_int64, E_GL_KHR_debug, E_GL_ARB_gpu_shader5, E_GL_ARB_multi_bind,
|
E_GL_ARB_gpu_shader_int64, E_GL_KHR_debug, E_GL_ARB_gpu_shader5, E_GL_ARB_multi_bind,
|
||||||
E_GL_ARB_shading_language_420pack, E_GL_ARB_vertex_attrib_binding, E_GL_ARB_shader_image_size,
|
E_GL_ARB_shading_language_420pack, E_GL_ARB_vertex_attrib_binding, E_GL_ARB_shader_image_size,
|
||||||
E_GL_ARB_explicit_attrib_location,
|
E_GL_ARB_explicit_attrib_location,
|
||||||
|
// Core since GL 3.1 and implemented for every version advertised here. The string
|
||||||
|
// matters because applications gate the ENTRY POINTS on it rather than on the
|
||||||
|
// version: a caller that finds the extension missing never resolves
|
||||||
|
// glGetUniformBlockIndex / glUniformBlockBinding, and one that then uses uniform
|
||||||
|
// blocks anyway calls through a null pointer.
|
||||||
|
E_GL_ARB_uniform_buffer_object,
|
||||||
|
// Sampling the stencil aspect through DEPTH_STENCIL_TEXTURE_MODE. Core from 4.3,
|
||||||
|
// so on a 4.0 context the string is the only way to reach it.
|
||||||
|
E_GL_ARB_stencil_texturing,
|
||||||
// Advertised with GL_NUM_PROGRAM_BINARY_FORMATS = 0, which the
|
// Advertised with GL_NUM_PROGRAM_BINARY_FORMATS = 0, which the
|
||||||
// extension explicitly permits. It is also the only thing that
|
// extension explicitly permits. It is also the only thing that
|
||||||
// exposes glProgramParameteri before GL 4.1.
|
// exposes glProgramParameteri before GL 4.1.
|
||||||
|
|||||||
@@ -950,7 +950,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
const TextureFormatInfo formatInfo = ResolveTextureFormatInfo(texture.GetFormat());
|
const TextureFormatInfo formatInfo = ResolveTextureFormatInfo(texture.GetFormat());
|
||||||
const VkComponentMapping sampledComponents = ResolveSampledViewComponents(texture, formatInfo);
|
const VkComponentMapping sampledComponents = ResolveSampledViewComponents(texture, formatInfo);
|
||||||
const VkImageAspectFlags sampledAspect = ResolveSampledImageViewAspectMask(resource->aspect);
|
const VkImageAspectFlags sampledAspect =
|
||||||
|
ResolveSampledImageViewAspectMask(resource->aspect, texture.GetDepthStencilTextureMode());
|
||||||
perMipSampledView = CreateImageView(resource->image, resource->format, sampledAspect, resource->viewType,
|
perMipSampledView = CreateImageView(resource->image, resource->format, sampledAspect, resource->viewType,
|
||||||
mipLevel, 1, 0, resource->arrayLayers, &sampledComponents);
|
mipLevel, 1, 0, resource->arrayLayers, &sampledComponents);
|
||||||
if (perMipSampledView == VK_NULL_HANDLE) {
|
if (perMipSampledView == VK_NULL_HANDLE) {
|
||||||
@@ -2238,7 +2239,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (resource.fullView == VK_NULL_HANDLE) {
|
if (resource.fullView == VK_NULL_HANDLE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const VkImageAspectFlags sampledAspect = ResolveSampledImageViewAspectMask(resource.aspect);
|
const VkImageAspectFlags sampledAspect =
|
||||||
|
ResolveSampledImageViewAspectMask(resource.aspect, texture.GetDepthStencilTextureMode());
|
||||||
resource.sampledView = CreateImageView(resource.image, resource.format, sampledAspect, resource.viewType,
|
resource.sampledView = CreateImageView(resource.image, resource.format, sampledAspect, resource.viewType,
|
||||||
baseMipLevel, levelCount, 0, resource.arrayLayers, &sampledComponents);
|
baseMipLevel, levelCount, 0, resource.arrayLayers, &sampledComponents);
|
||||||
if (resource.sampledView == VK_NULL_HANDLE) {
|
if (resource.sampledView == VK_NULL_HANDLE) {
|
||||||
@@ -2860,10 +2862,19 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageAspectFlags VkTextureManager::ResolveSampledImageViewAspectMask(VkImageAspectFlags imageAspect) {
|
VkImageAspectFlags VkTextureManager::ResolveSampledImageViewAspectMask(VkImageAspectFlags imageAspect,
|
||||||
|
GLenum depthStencilTextureMode) {
|
||||||
if ((imageAspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
|
if ((imageAspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
|
||||||
return VK_IMAGE_ASPECT_COLOR_BIT;
|
return VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
}
|
}
|
||||||
|
// A sampled view of a combined depth/stencil image may name exactly one aspect
|
||||||
|
// (VUID-VkDescriptorImageInfo-imageView-01976), and GL_DEPTH_STENCIL_TEXTURE_MODE is
|
||||||
|
// what picks it - the whole content of GL_ARB_stencil_texturing. Depth stays the
|
||||||
|
// default, so nothing that never sets the mode changes shape. The texture's params
|
||||||
|
// version moves with the mode, which is what makes the cached views be rebuilt.
|
||||||
|
if (depthStencilTextureMode == GL_STENCIL_INDEX && (imageAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0) {
|
||||||
|
return VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
}
|
||||||
if ((imageAspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0) {
|
if ((imageAspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0) {
|
||||||
return VK_IMAGE_ASPECT_DEPTH_BIT;
|
return VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -379,7 +379,11 @@ public:
|
|||||||
// true - a false positive merely ends the render pass, a false negative would skip a barrier.
|
// true - a false positive merely ends the render pass, a false negative would skip a barrier.
|
||||||
Bool NeedsStorageImagePreparation(MG_State::GLState::ITextureObject& texture) const;
|
Bool NeedsStorageImagePreparation(MG_State::GLState::ITextureObject& texture) const;
|
||||||
|
|
||||||
static VkImageAspectFlags ResolveSampledImageViewAspectMask(VkImageAspectFlags imageAspect);
|
// `depthStencilTextureMode` is the texture's GL_DEPTH_STENCIL_TEXTURE_MODE; it only decides
|
||||||
|
// anything for an image that carries both aspects. Defaulted so the call sites that have no
|
||||||
|
// texture in hand keep the depth-aspect answer they have always given.
|
||||||
|
static VkImageAspectFlags ResolveSampledImageViewAspectMask(VkImageAspectFlags imageAspect,
|
||||||
|
GLenum depthStencilTextureMode = GL_DEPTH_COMPONENT);
|
||||||
static VkFormat ResolveSampledImageViewFormat(VkFormat imageFormat, SamplerNumericDomain numericDomain);
|
static VkFormat ResolveSampledImageViewFormat(VkFormat imageFormat, SamplerNumericDomain numericDomain);
|
||||||
static Bool AreSampledImageViewFormatsCompatible(VkFormat imageFormat, VkFormat viewFormat);
|
static Bool AreSampledImageViewFormatsCompatible(VkFormat imageFormat, VkFormat viewFormat);
|
||||||
static Bool AreStorageImageViewFormatsCompatible(VkFormat imageFormat, VkFormat viewFormat);
|
static Bool AreStorageImageViewFormatsCompatible(VkFormat imageFormat, VkFormat viewFormat);
|
||||||
|
|||||||
@@ -1259,7 +1259,15 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName, "instancecount must be non-negative."));
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName, "instancecount must be non-negative."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!MG_State::pGLContext->ValidateTransformFeedbackName(id)) {
|
// "id is not the name of a transform feedback object" has to mean the same thing here
|
||||||
|
// as it does to glIsTransformFeedback, and the two predicates are not interchangeable:
|
||||||
|
// a name glGenTransformFeedbacks handed out is only reserved until it is first bound,
|
||||||
|
// and only the bind turns it into an object (GL 4.6 core 13.2.1). ValidateTransformFeedbackName
|
||||||
|
// answers the reservation question - the right one for glBindTransformFeedback, which is
|
||||||
|
// what turns a reserved name into an object - so using it here let a generated-but-unbound
|
||||||
|
// name through to the completed-span check below and raised INVALID_OPERATION where the
|
||||||
|
// spec asks for INVALID_VALUE. Name 0 is the default object and always drawable.
|
||||||
|
if (id != 0 && !MG_State::pGLContext->IsTransformFeedbackObject(id)) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidValue,
|
ErrorCode::InvalidValue,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName,
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName,
|
||||||
|
|||||||
@@ -117,7 +117,15 @@ namespace MobileGL::MG_State::GLState {
|
|||||||
void SetFixedSampleLocations(Bool fixedSampleLocations) override;
|
void SetFixedSampleLocations(Bool fixedSampleLocations) override;
|
||||||
Uint64 GetLifetimeId() const override;
|
Uint64 GetLifetimeId() const override;
|
||||||
GLenum GetDepthStencilTextureMode() const override { return m_depthStencilTextureMode; }
|
GLenum GetDepthStencilTextureMode() const override { return m_depthStencilTextureMode; }
|
||||||
void SetDepthStencilTextureMode(GLenum mode) override { m_depthStencilTextureMode = mode; }
|
// Bumps the params version like every other backend-visible texture parameter: the mode
|
||||||
|
// decides which ASPECT of a packed depth/stencil image a sampler reads, which DirectGLES
|
||||||
|
// forwards as a texture parameter and DirectVulkan bakes into the sampled image view. A
|
||||||
|
// silent write here would leave both backends showing the aspect they last built.
|
||||||
|
void SetDepthStencilTextureMode(GLenum mode) override {
|
||||||
|
if (m_depthStencilTextureMode == mode) return;
|
||||||
|
m_depthStencilTextureMode = mode;
|
||||||
|
++m_textureParamsVersion;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static Uint64 AllocateLifetimeId();
|
static Uint64 AllocateLifetimeId();
|
||||||
|
|||||||
@@ -198,6 +198,38 @@ TEST(DirectGLESSanity, AdvertisesDepthTextureForGlmarkShadowScenes) {
|
|||||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_depth_texture), extensions.end());
|
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_depth_texture), extensions.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Two strings that name capabilities MobileGL has always had, and that were missing from the
|
||||||
|
// advertised list for as long as it existed.
|
||||||
|
//
|
||||||
|
// GL_ARB_uniform_buffer_object is the one with teeth: applications gate the ENTRY POINTS on the
|
||||||
|
// string rather than on the context version. KHR-GL4x.transform_feedback.draw_xfb_instanced_test
|
||||||
|
// resolves glGetUniformBlockIndex / glUniformBlockBinding only inside `if (is_arb_ubo)`, then
|
||||||
|
// calls them unconditionally because the context claims >= 4.2 - so a missing string turned into
|
||||||
|
// a call through a null pointer and took the whole process down with SIGSEGV. Withdrawing it
|
||||||
|
// again would restore that crash on both backends.
|
||||||
|
//
|
||||||
|
// GL_ARB_stencil_texturing is what makes DEPTH_STENCIL_TEXTURE_MODE = GL_STENCIL_INDEX reachable
|
||||||
|
// at all before GL 4.3, which is the whole of KHR-GL3x.packed_depth_stencil.stencil_texturing.
|
||||||
|
TEST(DirectGLESSanity, AdvertisesUniformBufferObjectAndStencilTexturing) {
|
||||||
|
MobileGL::MG_Backend::DirectGLES::BackendObject_DirectGLES backend;
|
||||||
|
const auto& extensions = backend.GetRendererInfo().RendererGLInfo.Extensions;
|
||||||
|
|
||||||
|
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_uniform_buffer_object),
|
||||||
|
extensions.end());
|
||||||
|
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_stencil_texturing),
|
||||||
|
extensions.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DirectVulkanSanity, AdvertisesUniformBufferObjectAndStencilTexturing) {
|
||||||
|
MobileGL::MG_Backend::DirectVulkan::BackendObject_DirectVulkan backend;
|
||||||
|
const auto& extensions = backend.GetRendererInfo().RendererGLInfo.Extensions;
|
||||||
|
|
||||||
|
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_uniform_buffer_object),
|
||||||
|
extensions.end());
|
||||||
|
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_stencil_texturing),
|
||||||
|
extensions.end());
|
||||||
|
}
|
||||||
|
|
||||||
// Voxy only ever needed the extensions, which stay advertised whatever the version is; the version
|
// Voxy only ever needed the extensions, which stay advertised whatever the version is; the version
|
||||||
// assertion just pins what the backend really reports, now that V_OpenGL40 is in the list.
|
// assertion just pins what the backend really reports, now that V_OpenGL40 is in the list.
|
||||||
TEST(DirectGLESSanity, AdvertisesVoxyRequiredRenderingExtensions) {
|
TEST(DirectGLESSanity, AdvertisesVoxyRequiredRenderingExtensions) {
|
||||||
@@ -435,6 +467,31 @@ TEST(DirectVulkanSanity, AdvertisesTextureStorageForDirectStateAccess) {
|
|||||||
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_texture_storage), extensions.end());
|
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_texture_storage), extensions.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A sampled view of a combined depth/stencil image may name exactly one aspect, and
|
||||||
|
// GL_DEPTH_STENCIL_TEXTURE_MODE picks which - the whole of GL_ARB_stencil_texturing on this
|
||||||
|
// backend. Depth remains the answer for everything that does not ask for stencil, including
|
||||||
|
// depth-only images asked for the stencil aspect they do not have.
|
||||||
|
TEST(DirectVulkanSanity, SampledViewAspectFollowsDepthStencilTextureMode) {
|
||||||
|
using MobileGL::MG_Backend::DirectVulkan::VkTextureManager;
|
||||||
|
constexpr VkImageAspectFlags kPacked = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
|
||||||
|
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(kPacked, GL_DEPTH_COMPONENT),
|
||||||
|
static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT));
|
||||||
|
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(kPacked, GL_STENCIL_INDEX),
|
||||||
|
static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_STENCIL_BIT));
|
||||||
|
// The default argument is the pre-existing behaviour, for the call sites with no texture.
|
||||||
|
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(kPacked),
|
||||||
|
static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT));
|
||||||
|
|
||||||
|
// Single-aspect images ignore the mode: there is only one aspect to name.
|
||||||
|
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(VK_IMAGE_ASPECT_DEPTH_BIT, GL_STENCIL_INDEX),
|
||||||
|
static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT));
|
||||||
|
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(VK_IMAGE_ASPECT_STENCIL_BIT, GL_DEPTH_COMPONENT),
|
||||||
|
static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_STENCIL_BIT));
|
||||||
|
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(VK_IMAGE_ASPECT_COLOR_BIT, GL_STENCIL_INDEX),
|
||||||
|
static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_COLOR_BIT));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(DirectVulkanSanity, RenderPassExtentUsesSwapchainSizeOnlyForDefaultFramebuffer) {
|
TEST(DirectVulkanSanity, RenderPassExtentUsesSwapchainSizeOnlyForDefaultFramebuffer) {
|
||||||
using MobileGL::MG_Backend::DirectVulkan::ResolveRenderPassFramebufferExtent;
|
using MobileGL::MG_Backend::DirectVulkan::ResolveRenderPassFramebufferExtent;
|
||||||
|
|
||||||
|
|||||||
@@ -323,6 +323,47 @@ namespace {
|
|||||||
static_cast<void>(parameterBuffer);
|
static_cast<void>(parameterBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A transform feedback name has two different truths and glDrawTransformFeedback used to ask
|
||||||
|
// for the wrong one. glGenTransformFeedbacks only RESERVES a name; the first
|
||||||
|
// glBindTransformFeedback is what creates the object (GL 4.6 core 13.2.1), and
|
||||||
|
// glIsTransformFeedback reports exactly that distinction. glDrawTransformFeedback's
|
||||||
|
// "id is not the name of a transform feedback object" INVALID_VALUE has to agree with
|
||||||
|
// glIsTransformFeedback, or a caller that picks an unused name the way
|
||||||
|
// KHR-GL4x.transform_feedback.api_errors_test does - increment until glIsTransformFeedback
|
||||||
|
// says false - gets a name the draw then accepts, and the draw falls through to a different
|
||||||
|
// error entirely (INVALID_OPERATION, "glEndTransformFeedback has never been called").
|
||||||
|
//
|
||||||
|
// The draw path itself needs a backend and a linked program before it reaches the name, which
|
||||||
|
// this GPU-free suite has neither of, so what is pinned here is the predicate pair the fix
|
||||||
|
// turns on: the two must not collapse back into one.
|
||||||
|
TEST_F(NegativeApiErrorsTest, ReservedTransformFeedbackNameIsNotYetAnObject) {
|
||||||
|
GLuint name = 0;
|
||||||
|
GenTransformFeedbacks(1, &name);
|
||||||
|
ASSERT_NE(name, 0u);
|
||||||
|
DrainErrors();
|
||||||
|
|
||||||
|
// Reserved, so it is a legal argument to glBindTransformFeedback...
|
||||||
|
EXPECT_TRUE(MG_State::pGLContext->ValidateTransformFeedbackName(name));
|
||||||
|
// ...but not an object yet, which is what a draw must key off.
|
||||||
|
EXPECT_FALSE(MG_State::pGLContext->IsTransformFeedbackObject(name));
|
||||||
|
EXPECT_EQ(IsTransformFeedback(name), GL_FALSE);
|
||||||
|
|
||||||
|
BindTransformFeedback(GL_TRANSFORM_FEEDBACK, name);
|
||||||
|
EXPECT_EQ(GetError(), GL_NO_ERROR);
|
||||||
|
|
||||||
|
EXPECT_TRUE(MG_State::pGLContext->ValidateTransformFeedbackName(name));
|
||||||
|
EXPECT_TRUE(MG_State::pGLContext->IsTransformFeedbackObject(name));
|
||||||
|
EXPECT_EQ(IsTransformFeedback(name), GL_TRUE);
|
||||||
|
|
||||||
|
// The default object is never "an object" by this predicate and is always drawable, so
|
||||||
|
// the draw path has to special-case it rather than reuse the answer directly.
|
||||||
|
EXPECT_FALSE(MG_State::pGLContext->IsTransformFeedbackObject(0));
|
||||||
|
EXPECT_TRUE(MG_State::pGLContext->ValidateTransformFeedbackName(0));
|
||||||
|
|
||||||
|
BindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
|
||||||
|
DrainErrors();
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(NegativeApiErrorsTest, TexStorage3DRejectsCompressedFormatsOnTexture3D) {
|
TEST_F(NegativeApiErrorsTest, TexStorage3DRejectsCompressedFormatsOnTexture3D) {
|
||||||
GLuint texture = 0;
|
GLuint texture = 0;
|
||||||
GenTextures(1, &texture);
|
GenTextures(1, &texture);
|
||||||
|
|||||||
@@ -1651,6 +1651,43 @@ TEST_F(TextureTest, AnUncompressedRespecificationClearsTheCompressedTag) {
|
|||||||
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GL_DEPTH_STENCIL_TEXTURE_MODE used to be a pure frontend shadow: stored, answered by
|
||||||
|
// glGetTexParameter, and never shown to a backend. Sampling therefore always read the depth
|
||||||
|
// aspect however the mode was set, which is the whole of
|
||||||
|
// KHR-GL3x.packed_depth_stencil.stencil_texturing. Both backends pick the aspect up through the
|
||||||
|
// texture-params version - DirectGLES re-emits glTexParameteri when it moves, DirectVulkan
|
||||||
|
// rebuilds the sampled image view - so the version bump is the load-bearing part, and a
|
||||||
|
// no-op write must not spend one (every bump costs DirectVulkan a view recreation).
|
||||||
|
TEST_F(TextureTest, DepthStencilTextureModeIsBackendVisibleThroughTheParamsVersion) {
|
||||||
|
GLuint texture = 0;
|
||||||
|
MG_Impl::GLImpl::GenTextures(1, &texture);
|
||||||
|
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
MG_Impl::GLImpl::TexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, 8, 8);
|
||||||
|
ASSERT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||||
|
|
||||||
|
const auto textureObject = MG_State::pGLContext->GetTextureObject(texture);
|
||||||
|
ASSERT_NE(textureObject, nullptr);
|
||||||
|
EXPECT_EQ(textureObject->GetDepthStencilTextureMode(), static_cast<GLenum>(GL_DEPTH_COMPONENT));
|
||||||
|
|
||||||
|
const Uint16 initialVersion = textureObject->GetTextureParamsVersion();
|
||||||
|
MG_Impl::GLImpl::TexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
|
||||||
|
ASSERT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||||
|
EXPECT_EQ(textureObject->GetDepthStencilTextureMode(), static_cast<GLenum>(GL_STENCIL_INDEX));
|
||||||
|
EXPECT_NE(textureObject->GetTextureParamsVersion(), initialVersion);
|
||||||
|
|
||||||
|
// Re-writing the value already in force is not a change and must not invalidate anything.
|
||||||
|
const Uint16 settledVersion = textureObject->GetTextureParamsVersion();
|
||||||
|
MG_Impl::GLImpl::TexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
|
||||||
|
ASSERT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||||
|
EXPECT_EQ(textureObject->GetTextureParamsVersion(), settledVersion);
|
||||||
|
|
||||||
|
// ...and going back to the depth aspect is a change again.
|
||||||
|
MG_Impl::GLImpl::TexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_DEPTH_COMPONENT);
|
||||||
|
ASSERT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||||
|
EXPECT_EQ(textureObject->GetDepthStencilTextureMode(), static_cast<GLenum>(GL_DEPTH_COMPONENT));
|
||||||
|
EXPECT_NE(textureObject->GetTextureParamsVersion(), settledVersion);
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// 8x8 RGTC1: 2x2 blocks of 8 bytes, so the stored image is 32 bytes and one block row is 16.
|
// 8x8 RGTC1: 2x2 blocks of 8 bytes, so the stored image is 32 bytes and one block row is 16.
|
||||||
constexpr GLsizei kRgtc1Size8x8 = 32;
|
constexpr GLsizei kRgtc1Size8x8 = 32;
|
||||||
|
|||||||
Reference in New Issue
Block a user