[Fix] (Program): count the tessellation control stage as a transform-feedback capture stage

This commit is contained in:
2026-08-27 10:48:20 -04:00
parent ebff4b21f7
commit 66867a41ba
5 changed files with 326 additions and 5 deletions
+8 -1
View File
@@ -710,8 +710,15 @@ namespace MobileGL::MG_State {
// must not, or failing the link and killing every draw. A capture stage with an
// empty list is not a reason to look further down: it is the answer, and
// glBeginTransformFeedback's INVALID_OPERATION is the correct consequence.
//
// The order is the pipeline read backwards and includes the tessellation CONTROL
// stage, which is a vertex-processing stage too (GL 4.6 core 11): it can only be
// the last one in a pipeline that has a TCS but no evaluation or geometry stage,
// which is why it sits after TessEval. Same four stages, same order, as
// ProgramLinkTask::ResolveTransformFeedbackVaryings - see rule (2).
for (const ShaderStage captureStage:
{ShaderStage::Geometry, ShaderStage::TessEval, ShaderStage::Vertex}) {
{ShaderStage::Geometry, ShaderStage::TessEval, ShaderStage::TessControl,
ShaderStage::Vertex}) {
if (!compositeHasStage[static_cast<SizeT>(captureStage)]) continue;
const auto& captureProgram = pipeline->GetStageProgram(captureStage);
if (!captureProgram) continue;
@@ -1910,10 +1910,18 @@ namespace MobileGL::MG_State::GLState {
return true;
}
// Capture happens at the last vertex-processing stage (geometry, then
// tessellation evaluation, then vertex).
// Capture happens at the last vertex-processing stage (geometry, then tessellation
// evaluation, then tessellation CONTROL, then vertex). All four are vertex-processing
// stages in GL 4.6 core 11 - the control shader included - and in a separable program
// whose only stage is a TCS it is the last one that exists, so it is the capture stage
// and such a program MUST link (GL 4.6 core 7.3/11.1.2.1; the conformance suite spells
// the API split out at esextcTessellationShaderXFB.cpp:390-416, where a non-ES context
// takes should_succeed=true). TessControl sits AFTER TessEvaluation so a complete
// pipeline still captures at the evaluation stage and only a TCS-only program falls
// through to it. If MobileGL ever serves an ES context this arm has to be gated on the
// advertised API: ES requires the very same link to FAIL.
const glslang::TIntermediate* captureIntermediate = nullptr;
for (EShLanguage stage : {EShLangGeometry, EShLangTessEvaluation, EShLangVertex}) {
for (EShLanguage stage : {EShLangGeometry, EShLangTessEvaluation, EShLangTessControl, EShLangVertex}) {
captureIntermediate = artifacts.program->getIntermediate(stage);
if (captureIntermediate != nullptr) {
break;
@@ -554,7 +554,8 @@ namespace MobileGL::MG_State::GLState {
// asked for is the safer of the two readings.
if (task->in.requestedXfbVaryings.empty()) {
for (const ShaderStage captureStage:
{ShaderStage::Geometry, ShaderStage::TessEval, ShaderStage::Vertex}) {
{ShaderStage::Geometry, ShaderStage::TessEval, ShaderStage::TessControl,
ShaderStage::Vertex}) {
Bool stagePresent = false;
for (const auto& shader : m_shaders) {
if (!shader || shader->GetShaderStage() != captureStage) continue;