Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 01641c7

Browse files
ShabbyXCommit Bot
authored andcommitted
Vulkan: Fix UtilsVk clear in non-zero subpass
Mid-render-pass clears (through UtilsVk) run on the current subpass, which in the presence of multisampled-render-to-texture unresolve would be subpass 1. The graphics pipeline for that draw call should set the correct subpass index. Bug: angleproject:4836 Change-Id: Iba4a03ea96a63b0f5d09c27e5283ff8a8b534e05 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2441509 Commit-Queue: Shahbaz Youssefi <[email protected]> Reviewed-by: Shahbaz Youssefi <[email protected]> Reviewed-by: Jamie Madill <[email protected]>
1 parent 6534a6f commit 01641c7

File tree

6 files changed

+239
-17
lines changed

6 files changed

+239
-17
lines changed

src/libANGLE/renderer/vulkan/ContextVk.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4687,6 +4687,11 @@ void ContextVk::restoreFinishedRenderPass(vk::Framebuffer *framebuffer)
46874687
}
46884688
}
46894689

4690+
uint32_t ContextVk::getCurrentSubpassIndex() const
4691+
{
4692+
return mGraphicsPipelineDesc->getSubpass();
4693+
}
4694+
46904695
angle::Result ContextVk::flushCommandsAndEndRenderPass()
46914696
{
46924697
// Ensure we flush the RenderPass *after* the prior commands.

src/libANGLE/renderer/vulkan/ContextVk.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,8 @@ class ContextVk : public ContextImpl, public vk::Context
593593
// TODO(https://anglebug.com/4968): Support multiple open render passes.
594594
void restoreFinishedRenderPass(vk::Framebuffer *framebuffer);
595595

596+
uint32_t getCurrentSubpassIndex() const;
597+
596598
egl::ContextPriority getContextPriority() const override { return mContextPriority; }
597599
angle::Result startRenderPass(gl::Rectangle renderArea, vk::CommandBuffer **commandBufferOut);
598600
void startNextSubpass();

src/libANGLE/renderer/vulkan/UtilsVk.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,6 +1429,9 @@ angle::Result UtilsVk::clearFramebuffer(ContextVk *contextVk,
14291429
// Note: depth test is disabled by default so this should be unnecessary, but works around an
14301430
// Intel bug on windows. http://anglebug.com/3348
14311431
pipelineDesc.setDepthWriteEnabled(false);
1432+
// Clears can be done on a currently open render pass, so make sure the correct subpass index is
1433+
// used.
1434+
pipelineDesc.setSubpass(contextVk->getCurrentSubpassIndex());
14321435

14331436
// Clear stencil by enabling stencil write with the right mask.
14341437
if (params.clearStencil)

src/libANGLE/renderer/vulkan/vk_cache_utils.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2228,6 +2228,16 @@ void GraphicsPipelineDesc::nextSubpass(GraphicsPipelineTransitionBits *transitio
22282228
updateSubpass(transition, mRasterizationAndMultisampleStateInfo.bits.subpass + 1);
22292229
}
22302230

2231+
void GraphicsPipelineDesc::setSubpass(uint32_t subpass)
2232+
{
2233+
SetBitField(mRasterizationAndMultisampleStateInfo.bits.subpass, subpass);
2234+
}
2235+
2236+
uint32_t GraphicsPipelineDesc::getSubpass() const
2237+
{
2238+
return mRasterizationAndMultisampleStateInfo.bits.subpass;
2239+
}
2240+
22312241
void GraphicsPipelineDesc::updateRenderPassDesc(GraphicsPipelineTransitionBits *transition,
22322242
const RenderPassDesc &renderPassDesc)
22332243
{

src/libANGLE/renderer/vulkan/vk_cache_utils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,8 @@ class GraphicsPipelineDesc final
670670
// Subpass
671671
void resetSubpass(GraphicsPipelineTransitionBits *transition);
672672
void nextSubpass(GraphicsPipelineTransitionBits *transition);
673+
void setSubpass(uint32_t subpass);
674+
uint32_t getSubpass() const;
673675

674676
private:
675677
void updateSubpass(GraphicsPipelineTransitionBits *transition, uint32_t subpass);

src/tests/gl_tests/MultisampledRenderToTextureTest.cpp

Lines changed: 217 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ class MultisampledRenderToTextureTest : public ANGLETest
101101
glDisable(GL_DEPTH_TEST);
102102
glDisable(GL_STENCIL_TEST);
103103
glDisable(GL_BLEND);
104+
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
104105
drawQuad(mCopyTextureProgram, essl1_shaders::PositionAttrib(), 0.5f);
105106

106107
// Expect that the rendered quad has the same color as the source texture
@@ -144,6 +145,7 @@ class MultisampledRenderToTextureTest : public ANGLETest
144145
void copyTexSubImageTestCommon(bool useRenderbuffer);
145146
void drawCopyThenBlendCommon(bool useRenderbuffer);
146147
void clearDrawCopyThenBlendSameProgramCommon(bool useRenderbuffer);
148+
void drawCopyDrawThenMaskedClearCommon(bool useRenderbuffer);
147149
void clearThenBlendCommon(bool useRenderbuffer);
148150

149151
GLProgram mCopyTextureProgram;
@@ -1066,6 +1068,14 @@ void MultisampledRenderToTextureTest::clearDrawCopyThenBlendSameProgramCommon(bo
10661068
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
10671069
ASSERT_GL_NO_ERROR();
10681070

1071+
// Blend green into it. This makes sure that the blend after the resolve doesn't have different
1072+
// state from the one used here.
1073+
glEnable(GL_BLEND);
1074+
glBlendFunc(GL_ONE, GL_ONE);
1075+
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
1076+
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
1077+
ASSERT_GL_NO_ERROR();
1078+
10691079
// Create a texture and copy into it.
10701080
GLTexture texture;
10711081
glBindTexture(GL_TEXTURE_2D, texture);
@@ -1077,35 +1087,31 @@ void MultisampledRenderToTextureTest::clearDrawCopyThenBlendSameProgramCommon(bo
10771087
// residing in the single-sampled texture, is available to the multisampled intermediate image
10781088
// for blending.
10791089

1080-
// Blend half-transparent green into the multisampled color buffer.
1081-
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 0.5f);
1082-
glEnable(GL_BLEND);
1083-
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1090+
// Blend blue into the multisampled color buffer.
1091+
glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f);
10841092
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
10851093
ASSERT_GL_NO_ERROR();
10861094

1087-
// Verify that the texture is now yellow
1088-
const GLColor kExpected(127, 127, 0, 191);
1089-
EXPECT_PIXEL_COLOR_NEAR(0, 0, kExpected, 1);
1090-
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, 0, kExpected, 1);
1091-
EXPECT_PIXEL_COLOR_NEAR(0, kSize - 1, kExpected, 1);
1092-
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, kExpected, 1);
1095+
// Verify that the texture is now white
1096+
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
1097+
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::white);
1098+
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::white);
1099+
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::white);
10931100

10941101
// Once again, clear and draw so the program is used again in the way it was first used.
10951102
glClear(GL_COLOR_BUFFER_BIT);
10961103
glDisable(GL_BLEND);
10971104
glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f);
10981105
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
10991106

1100-
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor::blue, 1);
1101-
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, 0, GLColor::blue, 1);
1102-
EXPECT_PIXEL_COLOR_NEAR(0, kSize - 1, GLColor::blue, 1);
1103-
EXPECT_PIXEL_COLOR_NEAR(kSize - 1, kSize - 1, GLColor::blue, 1);
1107+
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
1108+
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::blue);
1109+
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::blue);
1110+
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::blue);
11041111

1105-
// For completeness, verify that the texture used as copy target is red.
1112+
// For completeness, verify that the texture used as copy target is yellow.
11061113
ASSERT_GL_NO_ERROR();
1107-
const GLColor kExpectedCopyResult(255, 0, 0, 255);
1108-
verifyResults(texture, kExpectedCopyResult, kSize, 0, 0, kSize, kSize);
1114+
verifyResults(texture, GLColor::yellow, kSize, 0, 0, kSize, kSize);
11091115

11101116
ASSERT_GL_NO_ERROR();
11111117
}
@@ -1126,6 +1132,200 @@ TEST_P(MultisampledRenderToTextureTest, RenderbufferClearDrawCopyThenBlendSamePr
11261132
clearDrawCopyThenBlendSameProgramCommon(true);
11271133
}
11281134

1135+
// Similar to RenderbufferClearDrawCopyThenBlendSameProgram, but with the depth/stencil attachment
1136+
// being unresolved only.
1137+
TEST_P(MultisampledRenderToTextureES3Test,
1138+
RenderbufferClearDrawCopyThenBlendWithDepthStencilSameProgram)
1139+
{
1140+
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
1141+
constexpr GLsizei kSize = 64;
1142+
1143+
setupCopyTexProgram();
1144+
1145+
GLFramebuffer fboMS;
1146+
glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
1147+
1148+
// Create multisampled framebuffer to draw into
1149+
GLTexture color;
1150+
glBindTexture(GL_TEXTURE_2D, color);
1151+
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1152+
glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color,
1153+
0, 4);
1154+
1155+
GLRenderbuffer depthStencil;
1156+
glBindRenderbuffer(GL_RENDERBUFFER, depthStencil);
1157+
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, kSize, kSize);
1158+
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
1159+
depthStencil);
1160+
ASSERT_GL_NO_ERROR();
1161+
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
1162+
1163+
// Draw red into the multisampled color buffer.
1164+
ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
1165+
glUseProgram(drawColor);
1166+
GLint colorUniformLocation =
1167+
glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
1168+
ASSERT_NE(colorUniformLocation, -1);
1169+
1170+
// Enable write to depth/stencil so the attachment has valid contents, but always pass the test.
1171+
glEnable(GL_DEPTH_TEST);
1172+
glDepthFunc(GL_ALWAYS);
1173+
1174+
glEnable(GL_STENCIL_TEST);
1175+
glStencilFunc(GL_ALWAYS, 0x55, 0xFF);
1176+
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
1177+
glStencilMask(0xFF);
1178+
1179+
// Clear the framebuffer.
1180+
glClearColor(0.1f, 0.9f, 0.2f, 0.8f);
1181+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1182+
1183+
// Then draw into it.
1184+
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
1185+
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 1.0f);
1186+
ASSERT_GL_NO_ERROR();
1187+
1188+
// Blend green into it. This makes sure that the blend after the resolve doesn't have different
1189+
// state from the one used here. Additionally, test that the previous draw output the correct
1190+
// depth/stencil data. Again, this makes sure that the draw call after the resolve doesn't have
1191+
// different has depth/stencil test state.
1192+
1193+
// If depth is not set to 1, rendering would fail.
1194+
glDepthFunc(GL_LESS);
1195+
1196+
// If stencil is not set to 0x55, rendering would fail.
1197+
glStencilFunc(GL_EQUAL, 0x55, 0xFF);
1198+
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
1199+
1200+
glEnable(GL_BLEND);
1201+
glBlendFunc(GL_ONE, GL_ONE);
1202+
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
1203+
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.95f);
1204+
ASSERT_GL_NO_ERROR();
1205+
1206+
// Create a texture and copy into it.
1207+
GLTexture texture;
1208+
glBindTexture(GL_TEXTURE_2D, texture);
1209+
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, kSize, kSize, 0);
1210+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1211+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1212+
1213+
// Clear color (but not depth/stencil), and draw again into the framebuffer, this time blending.
1214+
// Additionally, make sure the depth/stencil data are retained.
1215+
1216+
// Clear color (to blue), but not depth/stencil.
1217+
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
1218+
glClear(GL_COLOR_BUFFER_BIT);
1219+
1220+
// Blend green into the multisampled color buffer.
1221+
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
1222+
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.9f);
1223+
ASSERT_GL_NO_ERROR();
1224+
1225+
// Verify that the texture is now cyan
1226+
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
1227+
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::cyan);
1228+
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::cyan);
1229+
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::cyan);
1230+
1231+
// Once again, clear and draw so the program is used again in the way it was first used.
1232+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1233+
glDisable(GL_BLEND);
1234+
glDepthFunc(GL_ALWAYS);
1235+
glStencilFunc(GL_ALWAYS, 0x55, 0xFF);
1236+
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
1237+
glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f);
1238+
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
1239+
1240+
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
1241+
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::blue);
1242+
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::blue);
1243+
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::blue);
1244+
1245+
// For completeness, verify that the texture used as copy target is yellow.
1246+
ASSERT_GL_NO_ERROR();
1247+
verifyResults(texture, GLColor::yellow, kSize, 0, 0, kSize, kSize);
1248+
1249+
ASSERT_GL_NO_ERROR();
1250+
}
1251+
1252+
void MultisampledRenderToTextureTest::drawCopyDrawThenMaskedClearCommon(bool useRenderbuffer)
1253+
{
1254+
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
1255+
constexpr GLsizei kSize = 64;
1256+
1257+
setupCopyTexProgram();
1258+
1259+
GLFramebuffer fboMS;
1260+
glBindFramebuffer(GL_FRAMEBUFFER, fboMS);
1261+
1262+
// Create multisampled framebuffer to draw into
1263+
GLTexture textureMS;
1264+
GLRenderbuffer renderbufferMS;
1265+
createAndAttachColorAttachment(useRenderbuffer, kSize, GL_COLOR_ATTACHMENT0, nullptr,
1266+
&textureMS, &renderbufferMS);
1267+
EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
1268+
1269+
// Draw red into the multisampled color buffer.
1270+
ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
1271+
glUseProgram(drawColor);
1272+
GLint colorUniformLocation =
1273+
glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
1274+
ASSERT_NE(colorUniformLocation, -1);
1275+
1276+
// Draw into framebuffer.
1277+
glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
1278+
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
1279+
ASSERT_GL_NO_ERROR();
1280+
1281+
// Create a texture and copy into it.
1282+
GLTexture texture;
1283+
glBindTexture(GL_TEXTURE_2D, texture);
1284+
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, kSize, kSize, 0);
1285+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1286+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1287+
1288+
// Draw again into the framebuffer, this time blending. Afterwards, issue a masked clear. This
1289+
// ensures that previous resolved data is unresolved, and mid-render-pass clears work correctly.
1290+
1291+
// Draw green into the multisampled color buffer.
1292+
glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
1293+
drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.5f);
1294+
ASSERT_GL_NO_ERROR();
1295+
1296+
// Issue a masked clear.
1297+
glClearColor(0.1f, 0.9f, 1.0f, 0.8f);
1298+
glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
1299+
glClear(GL_COLOR_BUFFER_BIT);
1300+
1301+
// Verify that the texture is now cyan
1302+
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
1303+
EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::cyan);
1304+
EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::cyan);
1305+
EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::cyan);
1306+
1307+
// For completeness, verify that the texture used as copy target is red.
1308+
ASSERT_GL_NO_ERROR();
1309+
verifyResults(texture, GLColor::red, kSize, 0, 0, kSize, kSize);
1310+
1311+
ASSERT_GL_NO_ERROR();
1312+
}
1313+
1314+
// Draw, copy, draw then issue a masked clear. The copy will make sure an implicit resolve
1315+
// happens. The second draw should retain the data written by the first draw command ("unresolve"
1316+
// operation). The final clear uses a draw call to perform the clear in the Vulkan backend, and it
1317+
// should use the correct subpass index.
1318+
TEST_P(MultisampledRenderToTextureTest, DrawCopyDrawThenMaskedClear)
1319+
{
1320+
drawCopyDrawThenMaskedClearCommon(false);
1321+
}
1322+
1323+
// Same as DrawCopyDrawThenMaskedClearCommon but with renderbuffers
1324+
TEST_P(MultisampledRenderToTextureTest, RenderbufferDrawCopyDrawThenMaskedClear)
1325+
{
1326+
drawCopyDrawThenMaskedClearCommon(true);
1327+
}
1328+
11291329
void MultisampledRenderToTextureTest::clearThenBlendCommon(bool useRenderbuffer)
11301330
{
11311331
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));

0 commit comments

Comments
 (0)