[Merge] (DirectGLES, ShaderTranspiler): land GL43 wave4 with the interface-block rename inside the L2 boundary

This commit is contained in:
2026-08-20 21:13:55 -04:00
42 changed files with 3280 additions and 96 deletions
+19 -7
View File
@@ -1572,9 +1572,6 @@ namespace MobileGL::MG_Impl::GLImpl {
case GL_LINE_WIDTH:
*params = static_cast<GLint>(MG_State::pGLContext->GetLineWidth());
return;
case GL_LAYER_PROVOKING_VERTEX:
*params = GL_LAST_VERTEX_CONVENTION;
return;
case GL_LOGIC_OP_MODE:
*params = static_cast<GLint>(MG_Util::ConvertLogicOperationToGLEnum(MG_State::pGLContext->GetLogicOp()));
return;
@@ -1664,7 +1661,11 @@ namespace MobileGL::MG_Impl::GLImpl {
*params = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::Multisample) ? GL_TRUE : GL_FALSE;
return;
case GL_MIN_MAP_BUFFER_ALIGNMENT:
*params = 64; // TODO
// The same constant the map paths align to (MG_State/GLState/BufferState/
// PipeResource.h), never a literal: this number is a PROMISE about the pointers
// glMapBuffer and glMapBufferRange return, and the two used to be unrelated - the
// query said 64 while the pointers came out of a std::vector aligned to 16.
*params = static_cast<GLint>(MG_State::GLState::MIN_MAP_BUFFER_ALIGNMENT);
return;
case GL_MAX_LABEL_LENGTH:
*params = 256; // TODO
@@ -2113,9 +2114,6 @@ namespace MobileGL::MG_Impl::GLImpl {
params[3] = vp.w();
return;
}
case GL_VIEWPORT_INDEX_PROVOKING_VERTEX:
*params = GL_LAST_VERTEX_CONVENTION;
return;
case GL_MAX_ELEMENT_INDEX:
*params = 1024 * 1024; // TODO
return;
@@ -2203,6 +2201,20 @@ namespace MobileGL::MG_Impl::GLImpl {
case GL_MAX_CLIP_DISTANCES:
*params = dynamicParameters.MaxClipDistances;
break;
// Both were a hard-coded GL_LAST_VERTEX_CONVENTION, derived from nothing. GL 4.6 table
// 23.65 permits GL_UNDEFINED_VERTEX for either, and that is what the backends report
// wherever they do not actually pin a convention - claiming one is a statement about
// which vertex of a primitive supplies gl_Layer / gl_ViewportIndex, and DirectGLES
// rasterizes only viewport 0 on a driver without GL_OES_viewport_array while
// DirectVulkan picks its provoking mode per pipeline. KHR-GLxx.viewport_array.query
// accepts all four values, and .provoking_vertex - which failed on both devices, in
// OPPOSITE directions - stops verifying as soon as either answer is undefined.
case GL_LAYER_PROVOKING_VERTEX:
*params = static_cast<GLint>(dynamicParameters.LayerProvokingVertex);
break;
case GL_VIEWPORT_INDEX_PROVOKING_VERTEX:
*params = static_cast<GLint>(dynamicParameters.ViewportIndexProvokingVertex);
break;
case GL_MAX_COLOR_TEXTURE_SAMPLES:
*params = std::max(dynamicParameters.MaxColorTextureSamples, GetAdvertisedMaxSamples());
break;
+57 -4
View File
@@ -3749,12 +3749,57 @@ namespace MobileGL::MG_Impl::GLImpl {
}
return GetCopyImageLevelSize(endpoint.Texture, uploadTarget, level);
}
// How far the region's z axis may reach. It does not mean the same thing on every target
// GL 4.6 core 18.3.2 accepts: on a CUBE MAP it selects among the six faces, which this
// frontend keeps as six separate one-slice upload targets - so the level's own extent
// says 1 and the real bound is 6. A cube-map ARRAY is one upload target whose depth
// already counts layer-faces, and a 1D array carries its layers on y (which is where GL
// puts them for this entry point too), so both are answered by the level extent.
Int GetCopyImageEndpointLayerCount(const MG_Backend::CopyImageEndpoint& endpoint,
const IntVec3& levelSize) {
if (!endpoint.IsRenderbuffer() && endpoint.Texture &&
endpoint.Texture->GetTarget() == TextureTarget::TextureCubeMap) {
return 6;
}
return std::max(levelSize.z(), 1);
}
// GL 4.6 core 18.3.2 requires INVALID_VALUE when the region exceeds either image's
// boundaries. The only bounds-shaped call this validator used to make was
// ValidateCopyImageBlockAlignment, whose first line returns true for every UNCOMPRESSED
// format - so no uncompressed copy was bounded at all, and the z extent could not be
// bounded even in principle because srcZ/dstZ never reached the validator. Texture
// endpoints were covered only by accident, through the ES driver's own error, which the
// DirectGLES backend logs and swallows rather than reporting; a GL_RENDERBUFFER endpoint
// got neither (KHR-GL43.copy_image.exceeding_boundaries).
Bool ValidateCopyImageRegionBounds(const MG_Backend::CopyImageEndpoint& endpoint, const IntVec3& levelSize,
GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth,
const char* endpointName) {
// An extent this frontend does not know cannot bound anything, and guessing would
// reject a copy GL allows. Every caller has already established that the level
// exists and that the image is complete, so this is a belt-and-braces guard.
if (levelSize.x() <= 0 || levelSize.y() <= 0) return true;
const Int layers = GetCopyImageEndpointLayerCount(endpoint, levelSize);
if (x >= 0 && y >= 0 && z >= 0 && static_cast<Int64>(x) + width <= levelSize.x() &&
static_cast<Int64>(y) + height <= levelSize.y() && static_cast<Int64>(z) + depth <= layers) {
return true;
}
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", "ValidateCopyImageSubData_State",
std::format("The {} region [{}, {}, {}] + [{} x {} x {}] does not fit inside the {} x {} x {} "
"image.",
endpointName, x, y, z, width, height, depth, levelSize.x(), levelSize.y(), layers)));
return false;
}
} // namespace
Bool ValidateCopyImageSubData_State(const MG_Backend::CopyImageEndpoint& src,
GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY,
GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ,
const MG_Backend::CopyImageEndpoint& dst,
GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY,
GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ,
GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) {
if (!ValidateCopyImageObjectExists(src, "source") ||
!ValidateCopyImageObjectExists(dst, "destination")) {
@@ -3849,6 +3894,14 @@ namespace MobileGL::MG_Impl::GLImpl {
dstLevelSize.x(), dstLevelSize.y(), "destination")) {
return false;
}
// One region extent, measured against both images: GL 4.6 core 18.3.2 gives the copy a
// single width/height/depth and requires it to fit in the source AND the destination.
if (!ValidateCopyImageRegionBounds(src, srcLevelSize, srcX, srcY, srcZ, srcWidth, srcHeight, srcDepth,
"source") ||
!ValidateCopyImageRegionBounds(dst, dstLevelSize, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth,
"destination")) {
return false;
}
return true;
}
@@ -6082,8 +6135,8 @@ namespace MobileGL::MG_Impl::GLImpl {
};
const MG_Backend::CopyImageEndpoint src = resolveEndpoint(srcName, srcTarget);
const MG_Backend::CopyImageEndpoint dst = resolveEndpoint(dstName, dstTarget);
if (!ValidateCopyImageSubData_State(src, srcTarget, srcLevel, srcX, srcY, dst, dstTarget,
dstLevel, dstX, dstY, srcWidth, srcHeight, srcDepth)) {
if (!ValidateCopyImageSubData_State(src, srcTarget, srcLevel, srcX, srcY, srcZ, dst, dstTarget,
dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth)) {
return;
}
CopyImageSubData_Backend(src, srcTarget, srcLevel, srcX, srcY, srcZ, dst, dstTarget, dstLevel,