From fb29ae9fa5d73b6157b0c4cae2e3dfb013d7f57f Mon Sep 17 00:00:00 2001 From: Philip Rideout Date: Fri, 12 Feb 2021 13:22:11 -0800 Subject: [PATCH] Add MSAA resolve (color and depth) to the blit test. --- filament/backend/test/test_Blit.cpp | 280 ++++++++++++++++++++++++++-- 1 file changed, 262 insertions(+), 18 deletions(-) diff --git a/filament/backend/test/test_Blit.cpp b/filament/backend/test/test_Blit.cpp index ea5f336e8e..1dd78f4cc1 100644 --- a/filament/backend/test/test_Blit.cpp +++ b/filament/backend/test/test_Blit.cpp @@ -180,16 +180,16 @@ TEST_F(BackendTest, ColorMagnify) { {0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel}, SamplerMagFilter::LINEAR); // Push through an empty frame to allow the texture to upload and the blit to execute. - getDriverApi().beginFrame(0, 0); - getDriverApi().commit(swapChain); - getDriverApi().endFrame(0); + api.beginFrame(0, 0); + api.commit(swapChain); + api.endFrame(0); // Grab a screenshot. ScreenshotParams params { kDstTexWidth, kDstTexHeight, "ColorMagnify.png" }; - getDriverApi().beginFrame(0, 0); + api.beginFrame(0, 0); dumpScreenshot(api, dstRenderTargets[0], ¶ms); - getDriverApi().commit(swapChain); - getDriverApi().endFrame(0); + api.commit(swapChain); + api.endFrame(0); // Wait for the ReadPixels result to come back. api.finish(); @@ -254,16 +254,16 @@ TEST_F(BackendTest, ColorMinify) { {0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel}, SamplerMagFilter::LINEAR); // Push through an empty frame to allow the texture to upload and the blit to execute. - getDriverApi().beginFrame(0, 0); - getDriverApi().commit(swapChain); - getDriverApi().endFrame(0); + api.beginFrame(0, 0); + api.commit(swapChain); + api.endFrame(0); // Grab a screenshot. ScreenshotParams params { kDstTexWidth, kDstTexHeight, "ColorMinify.png" }; - getDriverApi().beginFrame(0, 0); + api.beginFrame(0, 0); dumpScreenshot(api, dstRenderTargets[0], ¶ms); - getDriverApi().commit(swapChain); - getDriverApi().endFrame(0); + api.commit(swapChain); + api.endFrame(0); // Wait for the ReadPixels result to come back. api.finish(); @@ -373,16 +373,16 @@ TEST_F(BackendTest, DepthMinify) { api.beginRenderPass(srcRenderTarget, params); api.draw(state, triangle->getRenderPrimitive()); api.endRenderPass(); - getDriverApi().endFrame(0); + api.endFrame(0); // Copy over the color buffer and the depth buffer. - const int srcLevel = 0; api.blit(TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH, dstRenderTarget, {0, 0, kDstTexWidth, kDstTexHeight}, srcRenderTarget, - {0, 0, kSrcTexWidth >> srcLevel, kSrcTexHeight >> srcLevel}, SamplerMagFilter::LINEAR); + {0, 0, kSrcTexWidth, kSrcTexHeight}, SamplerMagFilter::LINEAR); // Draw a larger blue triangle into dstRenderTarget. We carefully place it below the red // triangle in order to exercise depth testing. + api.beginFrame(0, 0); params.viewport.width = kDstTexWidth; params.viewport.height = kDstTexHeight; params.flags.clear = TargetBufferFlags::NONE; @@ -393,13 +393,14 @@ TEST_F(BackendTest, DepthMinify) { api.beginRenderPass(dstRenderTarget, params); api.draw(state, triangle->getRenderPrimitive()); api.endRenderPass(); + api.endFrame(0); // Grab a screenshot. ScreenshotParams sparams { kDstTexWidth, kDstTexHeight, "DepthBlit.png" }; - getDriverApi().beginFrame(0, 0); + api.beginFrame(0, 0); dumpScreenshot(api, dstRenderTarget, &sparams); - getDriverApi().commit(swapChain); - getDriverApi().endFrame(0); + api.commit(swapChain); + api.endFrame(0); // Wait for the ReadPixels result to come back. api.finish(); @@ -425,4 +426,247 @@ TEST_F(BackendTest, DepthMinify) { executeCommands(); } +TEST_F(BackendTest, ColorResolve) { + auto& api = getDriverApi(); + + constexpr int kSrcTexWidth = 256; + constexpr int kSrcTexHeight = 256; + constexpr int kDstTexWidth = 256; + constexpr int kDstTexHeight = 256; + constexpr auto kColorTexFormat = TextureFormat::RGBA8; + constexpr int kSampleCount = 4; + + // Create a SwapChain and make it current. We don't really use it so the res doesn't matter. + auto swapChain = api.createSwapChainHeadless(256, 256, 0); + api.makeCurrent(swapChain, swapChain); + + // Create a program. + ProgramHandle program; + { + ShaderGenerator shaderGen(triangleVs, triangleFs, sBackend, sIsMobilePlatform); + Program prog = shaderGen.getProgram(); + Program::Sampler psamplers[] = { utils::CString("tex"), 0, false }; + prog.setSamplerGroup(0, psamplers, sizeof(psamplers) / sizeof(psamplers[0])); + prog.setUniformBlock(1, utils::CString("params")); + program = api.createProgram(std::move(prog)); + } + + // Create a VertexBuffer, IndexBuffer, and RenderPrimitive. + TrianglePrimitive* triangle = new TrianglePrimitive(api); + + // Create 4-sample texture. + Handle srcColorTexture = api.createTexture( + SamplerType::SAMPLER_2D, 1, kColorTexFormat, kSampleCount, kSrcTexWidth, kSrcTexHeight, 1, + TextureUsage::COLOR_ATTACHMENT); + + // Create 1-sample texture. + Handle dstColorTexture = api.createTexture( + SamplerType::SAMPLER_2D, 1, kColorTexFormat, 1, kDstTexWidth, kDstTexHeight, 1, + TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT); + + // Create a 4-sample render target with the 4-sample texture. + Handle srcRenderTarget = api.createRenderTarget( + TargetBufferFlags::COLOR, kSrcTexWidth, kSrcTexHeight, kSampleCount, { srcColorTexture }, {}, {}); + + // Create a 1-sample render target with the 1-sample texture. + Handle dstRenderTarget = api.createRenderTarget( + TargetBufferFlags::COLOR, kDstTexWidth, kDstTexHeight, 1, { dstColorTexture }, {}, {}); + + // Prep for rendering. + RenderPassParams params = {}; + params.flags.clear = TargetBufferFlags::COLOR; + params.clearColor = float4(1, 1, 0, 1); + params.viewport.width = kSrcTexWidth; + params.viewport.height = kSrcTexHeight; + + PipelineState state = {}; + state.rasterState.colorWrite = true; + state.rasterState.culling = RasterState::CullingMode::NONE; + state.program = program; + auto ubuffer = api.createUniformBuffer(sizeof(MaterialParams), BufferUsage::STATIC); + api.makeCurrent(swapChain, swapChain); + api.beginFrame(0, 0); + api.bindUniformBuffer(0, ubuffer); + + // Draw red triangle into srcRenderTarget. + uploadUniforms(api, ubuffer, { + .color = float4(1, 0, 0, 1), + .scale = float4(1, 1, 0.5, 0), + }); + api.beginRenderPass(srcRenderTarget, params); + api.draw(state, triangle->getRenderPrimitive()); + api.endRenderPass(); + api.endFrame(0); + + // Resolve the MSAA render target into the single-sample render target. + api.blit(TargetBufferFlags::COLOR, dstRenderTarget, + {0, 0, kDstTexWidth, kDstTexHeight}, srcRenderTarget, + {0, 0, kSrcTexWidth, kSrcTexHeight}, SamplerMagFilter::LINEAR); + + // Grab a screenshot. + ScreenshotParams sparams { kDstTexWidth, kDstTexHeight, "ColorResolve.png" }; + api.beginFrame(0, 0); + dumpScreenshot(api, dstRenderTarget, &sparams); + api.commit(swapChain); + api.endFrame(0); + + // Wait for the ReadPixels result to come back. + api.finish(); + executeCommands(); + getDriver().purge(); + + // Check if the image matches perfectly to our golden run. + const uint32_t expected = 0xebfac2ef; + printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", sparams.pixelHashResult, expected); + EXPECT_TRUE(sparams.pixelHashResult == expected); + + // Cleanup. + api.destroyUniformBuffer(ubuffer); + api.destroyProgram(program); + api.destroyTexture(srcColorTexture); + api.destroyTexture(dstColorTexture); + api.destroySwapChain(swapChain); + api.destroyRenderTarget(srcRenderTarget); + api.destroyRenderTarget(dstRenderTarget); + delete triangle; + executeCommands(); +} + +TEST_F(BackendTest, DepthResolve) { + auto& api = getDriverApi(); + + constexpr int kSrcTexWidth = 256; + constexpr int kSrcTexHeight = 256; + constexpr int kDstTexWidth = 256; + constexpr int kDstTexHeight = 256; + constexpr auto kColorTexFormat = TextureFormat::RGBA8; + constexpr auto kDepthTexFormat = TextureFormat::DEPTH24; + constexpr int kSampleCount = 4; + + // Create a SwapChain and make it current. We don't really use it so the res doesn't matter. + auto swapChain = api.createSwapChainHeadless(256, 256, 0); + api.makeCurrent(swapChain, swapChain); + + // Create a program. + ProgramHandle program; + { + ShaderGenerator shaderGen(triangleVs, triangleFs, sBackend, sIsMobilePlatform); + Program prog = shaderGen.getProgram(); + Program::Sampler psamplers[] = { utils::CString("tex"), 0, false }; + prog.setSamplerGroup(0, psamplers, sizeof(psamplers) / sizeof(psamplers[0])); + prog.setUniformBlock(1, utils::CString("params")); + program = api.createProgram(std::move(prog)); + } + + // Create a VertexBuffer, IndexBuffer, and RenderPrimitive. + TrianglePrimitive* triangle = new TrianglePrimitive(api); + + // Create 4-sample textures. + Handle srcColorTexture = api.createTexture( + SamplerType::SAMPLER_2D, 1, kColorTexFormat, kSampleCount, kSrcTexWidth, kSrcTexHeight, 1, + TextureUsage::COLOR_ATTACHMENT); + + Handle srcDepthTexture = api.createTexture( + SamplerType::SAMPLER_2D, 1, kDepthTexFormat, kSampleCount, kSrcTexWidth, kSrcTexHeight, 1, + TextureUsage::DEPTH_ATTACHMENT); + + // Create 1-sample textures. + Handle dstColorTexture = api.createTexture( + SamplerType::SAMPLER_2D, 1, kColorTexFormat, 1, kDstTexWidth, kDstTexHeight, 1, + TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT); + + Handle dstDepthTexture = api.createTexture( + SamplerType::SAMPLER_2D, 1, kDepthTexFormat, 1, kDstTexWidth, kDstTexHeight, 1, + TextureUsage::DEPTH_ATTACHMENT); + + // Create a 4-sample render target with 4-sample textures. + Handle srcRenderTarget = api.createRenderTarget( + TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH, kSrcTexWidth, kSrcTexHeight, + kSampleCount, { srcColorTexture }, { srcDepthTexture }, {}); + + // Create a 1-sample render target with 1-sample textures. + Handle dstRenderTarget = api.createRenderTarget( + TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH, kDstTexWidth, kDstTexHeight, + 1, { dstColorTexture }, { dstDepthTexture }, {}); + + // Prep for rendering. + RenderPassParams params = {}; + params.flags.clear = TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH; + params.clearColor = float4(1, 1, 0, 1); + params.clearDepth = 1.0; + params.flags.discardEnd = TargetBufferFlags::NONE; + params.viewport.width = kSrcTexWidth; + params.viewport.height = kSrcTexHeight; + + PipelineState state = {}; + state.rasterState.colorWrite = true; + state.rasterState.depthWrite = true; + state.rasterState.depthFunc = RasterState::DepthFunc::L; + state.rasterState.culling = RasterState::CullingMode::NONE; + state.program = program; + auto ubuffer = api.createUniformBuffer(sizeof(MaterialParams), BufferUsage::STATIC); + api.makeCurrent(swapChain, swapChain); + api.beginFrame(0, 0); + api.bindUniformBuffer(0, ubuffer); + + // Draw red triangle into srcRenderTarget. + uploadUniforms(api, ubuffer, { + .color = float4(1, 0, 0, 1), + .scale = float4(1, 1, 0.5, 0), + }); + api.beginRenderPass(srcRenderTarget, params); + api.draw(state, triangle->getRenderPrimitive()); + api.endRenderPass(); + api.endFrame(0); + + // Resolve the MSAA color and depth buffers into the single-sample render target. + api.blit(TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH, dstRenderTarget, + {0, 0, kDstTexWidth, kDstTexHeight}, srcRenderTarget, + {0, 0, kSrcTexWidth, kSrcTexHeight}, SamplerMagFilter::LINEAR); + + // Draw a larger blue triangle into dstRenderTarget. We carefully place it below the red + // triangle in order to exercise depth testing. + api.beginFrame(0, 0); + params.viewport.width = kDstTexWidth; + params.viewport.height = kDstTexHeight; + params.flags.clear = TargetBufferFlags::NONE; + uploadUniforms(api, ubuffer, { + .color = float4(0, 0, 1, 1), + .scale = float4(1.2, 1.2, 0.75, 0), + }); + api.beginRenderPass(dstRenderTarget, params); + api.draw(state, triangle->getRenderPrimitive()); + api.endRenderPass(); + + // Grab a screenshot. + ScreenshotParams sparams { kDstTexWidth, kDstTexHeight, "DepthResolve.png" }; + api.beginFrame(0, 0); + dumpScreenshot(api, dstRenderTarget, &sparams); + api.commit(swapChain); + api.endFrame(0); + + // Wait for the ReadPixels result to come back. + api.finish(); + executeCommands(); + getDriver().purge(); + + // Check if the image matches perfectly to our golden run. + const uint32_t expected = 0x5a38e6ba; + printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", sparams.pixelHashResult, expected); + EXPECT_TRUE(sparams.pixelHashResult == expected); + + // Cleanup. + api.destroyUniformBuffer(ubuffer); + api.destroyProgram(program); + api.destroyTexture(srcColorTexture); + api.destroyTexture(dstColorTexture); + api.destroyTexture(srcDepthTexture); + api.destroyTexture(dstDepthTexture); + api.destroySwapChain(swapChain); + api.destroyRenderTarget(srcRenderTarget); + api.destroyRenderTarget(dstRenderTarget); + delete triangle; + executeCommands(); +} + } // namespace test