@@ -1046,6 +1046,142 @@ TEST_P(RendererTest, VertexBufferBuilder) {
10461046 ASSERT_EQ (vertex_builder.GetVertexCount (), 4u );
10471047}
10481048
1049+ TEST_P (RendererTest, StencilMask) {
1050+ using VS = BoxFadeVertexShader;
1051+ using FS = BoxFadeFragmentShader;
1052+ auto context = GetContext ();
1053+ ASSERT_TRUE (context);
1054+ using BoxFadePipelineBuilder = PipelineBuilder<VS, FS>;
1055+ auto desc = BoxFadePipelineBuilder::MakeDefaultPipelineDescriptor (*context);
1056+ ASSERT_TRUE (desc.has_value ());
1057+
1058+ // Vertex buffer.
1059+ VertexBufferBuilder<VS::PerVertexData> vertex_builder;
1060+ vertex_builder.SetLabel (" Box" );
1061+ vertex_builder.AddVertices ({
1062+ {{100 , 100 , 0.0 }, {0.0 , 0.0 }}, // 1
1063+ {{800 , 100 , 0.0 }, {1.0 , 0.0 }}, // 2
1064+ {{800 , 800 , 0.0 }, {1.0 , 1.0 }}, // 3
1065+ {{100 , 100 , 0.0 }, {0.0 , 0.0 }}, // 1
1066+ {{800 , 800 , 0.0 }, {1.0 , 1.0 }}, // 3
1067+ {{100 , 800 , 0.0 }, {0.0 , 1.0 }}, // 4
1068+ });
1069+ auto vertex_buffer =
1070+ vertex_builder.CreateVertexBuffer (*context->GetResourceAllocator ());
1071+ ASSERT_TRUE (vertex_buffer);
1072+
1073+ desc->SetSampleCount (SampleCount::kCount4 );
1074+
1075+ auto bridge = CreateTextureForFixture (" bay_bridge.jpg" );
1076+ auto boston = CreateTextureForFixture (" boston.jpg" );
1077+ ASSERT_TRUE (bridge && boston);
1078+ auto sampler = context->GetSamplerLibrary ()->GetSampler ({});
1079+ ASSERT_TRUE (sampler);
1080+
1081+ static bool mirror = false ;
1082+ static int stencil_reference_write = 0xFF ;
1083+ static int stencil_reference_read = 0x1 ;
1084+ std::vector<uint8_t > stencil_contents;
1085+ static int last_stencil_contents_reference_value = 0 ;
1086+ Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
1087+ auto buffer = context->CreateCommandBuffer ();
1088+ if (!buffer) {
1089+ return false ;
1090+ }
1091+ buffer->SetLabel (" Playground Command Buffer" );
1092+
1093+ {
1094+ // Configure the stencil attachment for the test.
1095+ RenderTarget::AttachmentConfig stencil_config;
1096+ stencil_config.load_action = LoadAction::kLoad ;
1097+ stencil_config.store_action = StoreAction::kDontCare ;
1098+ stencil_config.storage_mode = StorageMode::kHostVisible ;
1099+ render_target.SetupStencilAttachment (*context,
1100+ render_target.GetRenderTargetSize (),
1101+ true , " stencil" , stencil_config);
1102+ // Fill the stencil buffer with an checkerboard pattern.
1103+ const auto target_width = render_target.GetRenderTargetSize ().width ;
1104+ const auto target_height = render_target.GetRenderTargetSize ().height ;
1105+ const size_t target_size = target_width * target_height;
1106+ if (stencil_contents.size () != target_size ||
1107+ last_stencil_contents_reference_value != stencil_reference_write) {
1108+ stencil_contents.resize (target_size);
1109+ last_stencil_contents_reference_value = stencil_reference_write;
1110+ for (int y = 0 ; y < target_height; y++) {
1111+ for (int x = 0 ; x < target_width; x++) {
1112+ const auto index = y * target_width + x;
1113+ const auto kCheckSize = 64 ;
1114+ const auto value =
1115+ (((y / kCheckSize ) + (x / kCheckSize )) % 2 == 0 ) *
1116+ stencil_reference_write;
1117+ stencil_contents[index] = value;
1118+ }
1119+ }
1120+ }
1121+ if (!render_target.GetStencilAttachment ()->texture ->SetContents (
1122+ stencil_contents.data (), stencil_contents.size (), 0 , false )) {
1123+ VALIDATION_LOG << " Could not upload stencil contents to device memory" ;
1124+ return false ;
1125+ }
1126+ auto pass = buffer->CreateRenderPass (render_target);
1127+ if (!pass) {
1128+ return false ;
1129+ }
1130+ pass->SetLabel (" Stencil Buffer" );
1131+ ImGui::Begin (" Controls" , nullptr , ImGuiWindowFlags_AlwaysAutoResize);
1132+ ImGui::SliderInt (" Stencil Write Value" , &stencil_reference_write, 0 ,
1133+ 0xFF );
1134+ ImGui::SliderInt (" Stencil Compare Value" , &stencil_reference_read, 0 ,
1135+ 0xFF );
1136+ ImGui::Checkbox (" Mirror" , &mirror);
1137+ ImGui::End ();
1138+ StencilAttachmentDescriptor front_and_back;
1139+ front_and_back.stencil_compare = CompareFunction::kLessEqual ;
1140+ desc->SetStencilAttachmentDescriptors (front_and_back);
1141+ auto pipeline = context->GetPipelineLibrary ()->GetPipeline (desc).Get ();
1142+
1143+ assert (pipeline && pipeline->IsValid ());
1144+
1145+ Command cmd;
1146+ cmd.label = " Box" ;
1147+ cmd.pipeline = pipeline;
1148+ cmd.stencil_reference = stencil_reference_read;
1149+
1150+ cmd.BindVertices (vertex_buffer);
1151+
1152+ VS::UniformBuffer uniforms;
1153+ uniforms.mvp = Matrix::MakeOrthographic (pass->GetRenderTargetSize ()) *
1154+ Matrix::MakeScale (GetContentScale ());
1155+ if (mirror) {
1156+ uniforms.mvp = Matrix::MakeScale (Vector2 (-1 , -1 )) * uniforms.mvp ;
1157+ }
1158+ VS::BindUniformBuffer (
1159+ cmd, pass->GetTransientsBuffer ().EmplaceUniform (uniforms));
1160+
1161+ FS::FrameInfo frame_info;
1162+ frame_info.current_time = GetSecondsElapsed ();
1163+ frame_info.cursor_position = GetCursorPosition ();
1164+ frame_info.window_size .x = GetWindowSize ().width ;
1165+ frame_info.window_size .y = GetWindowSize ().height ;
1166+
1167+ FS::BindFrameInfo (cmd,
1168+ pass->GetTransientsBuffer ().EmplaceUniform (frame_info));
1169+ FS::BindContents1 (cmd, boston, sampler);
1170+ FS::BindContents2 (cmd, bridge, sampler);
1171+ if (!pass->AddCommand (std::move (cmd))) {
1172+ return false ;
1173+ }
1174+ pass->EncodeCommands ();
1175+ }
1176+
1177+ if (!buffer->SubmitCommands ()) {
1178+ return false ;
1179+ }
1180+ return true ;
1181+ };
1182+ OpenPlaygroundHere (callback);
1183+ }
1184+
10491185} // namespace testing
10501186} // namespace impeller
10511187
0 commit comments