From 677cdc1239711bf00a5b3c1c655cec6532d84804 Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Thu, 7 Jul 2022 17:22:41 -0700 Subject: [PATCH] Add backend test for viewport and scissor (#5767) --- filament/backend/CMakeLists.txt | 1 + filament/backend/test/BackendTest.cpp | 2 +- filament/backend/test/test_Scissor.cpp | 167 +++++++++++++++++++++++++ 3 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 filament/backend/test/test_Scissor.cpp diff --git a/filament/backend/CMakeLists.txt b/filament/backend/CMakeLists.txt index ee9095598e..15c9af36ea 100644 --- a/filament/backend/CMakeLists.txt +++ b/filament/backend/CMakeLists.txt @@ -395,6 +395,7 @@ if (APPLE) test/test_LoadImage.cpp test/test_RenderExternalImage.cpp test/test_StencilBuffer.cpp + test/test_Scissor.cpp ) target_link_libraries(backend_test PRIVATE diff --git a/filament/backend/test/BackendTest.cpp b/filament/backend/test/BackendTest.cpp index e5e0e23abf..59bb2c3427 100644 --- a/filament/backend/test/BackendTest.cpp +++ b/filament/backend/test/BackendTest.cpp @@ -181,7 +181,7 @@ void BackendTest::readPixelsAndAssertHash(const char* testName, size_t width, si free(c->name); free(c); }, (void*)c); - getDriverApi().readPixels(rt, 0, 0, 512, 512, std::move(pbd)); + getDriverApi().readPixels(rt, 0, 0, width, height, std::move(pbd)); } class Environment : public ::testing::Environment { diff --git a/filament/backend/test/test_Scissor.cpp b/filament/backend/test/test_Scissor.cpp new file mode 100644 index 0000000000..f5ee62f5b2 --- /dev/null +++ b/filament/backend/test/test_Scissor.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BackendTest.h" + +#include "ShaderGenerator.h" +#include "TrianglePrimitive.h" + +#include + +namespace test { + +using namespace filament; +using namespace filament::backend; + +static const char* const triangleVs = R"(#version 450 core +layout(location = 0) in vec4 mesh_position; +void main() { + gl_Position = vec4(mesh_position.xy, 0.0, 1.0); +#if defined(TARGET_VULKAN_ENVIRONMENT) + // In Vulkan, clip space is Y-down. In OpenGL and Metal, clip space is Y-up. + gl_Position.y = -gl_Position.y; +#endif +})"; + +static const char* const triangleFs = R"(#version 450 core +precision mediump int; precision highp float; +layout(location = 0) out vec4 fragColor; +void main() { + fragColor = vec4(1.0f); +})"; + +TEST_F(BackendTest, ScissorViewportRegion) { + auto& api = getDriverApi(); + + constexpr int kSrcTexWidth = 1024; + constexpr int kSrcTexHeight = 1024; + constexpr auto kSrcTexFormat = TextureFormat::RGBA8; + constexpr int kNumLevels = 3; + constexpr int kSrcLevel = 1; + constexpr int kSrcRtWidth = 384; + constexpr int kSrcRtHeight = 384; + + api.startCapture(0); + + // color texture (mip level 1) 512x512 depth texture (mip level 0) 512x512 + // +----------------------------------------+ +------------------------------------------+ + // | | | | + // | | | | + // | RenderTarget (384x384) | | RenderTarget (384x384) | + // +------------------------------+ | +------------------------------+ | + // | | | | | | + // | +-------------------+ | | | | | + // | | viewport | | | | | | + // | | | | | | | | + // | +---+---------------+ | | | | | | + // | | | | | | | | | | + // | | | | | | | | | | + // | | | (64,64) | | | | | | | + // | | +---------------+---+ | | | | | + // | | scissor | | | | | | + // | +-------------------+ | | | | | + // | (32, 32) | | | | | + // +------------------------------+---------+ +------------------------------+-----------+ + + // The test is executed within this block scope to force destructors to run before + // executeCommands(). + { + // 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. + ShaderGenerator shaderGen(triangleVs, triangleFs, sBackend, sIsMobilePlatform); + Program p = shaderGen.getProgram(); + ProgramHandle program = api.createProgram(std::move(p)); + + // Create source color and depth textures. + Handle srcTexture = api.createTexture(SamplerType::SAMPLER_2D, kNumLevels, + kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1, + TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT); + Handle depthTexture = api.createTexture(SamplerType::SAMPLER_2D, 1, + TextureFormat::DEPTH16, 1, 512, 512, 1, + TextureUsage::DEPTH_ATTACHMENT); + + // Render into the bottom-left quarter of the texture. + Viewport srcRect = { + .left = 64, + .bottom = 64, + .width = kSrcRtWidth - 64 * 2, + .height = kSrcRtHeight - 64 * 2 + }; + Viewport scissor = { + .left = 32, + .bottom = 32, + .width = kSrcRtWidth - 64 * 2, + .height = kSrcRtHeight - 64 * 2 + }; + + // We purposely set the render target width and height to smaller than the texture, to check + // that this case is handled correctly. + Handle srcRenderTarget = api.createRenderTarget( + TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH, kSrcRtHeight, kSrcRtHeight, 1, + {srcTexture, kSrcLevel, 0}, {depthTexture, 0, 0}, {}); + + Handle fullRenderTarget = api.createRenderTarget(TargetBufferFlags::COLOR, + kSrcTexHeight >> kSrcLevel, kSrcTexWidth >> kSrcLevel, 1, + {srcTexture, kSrcLevel, 0}, {}, {}); + + TrianglePrimitive triangle(api); + + // Render a white triangle over blue. + RenderPassParams params = {}; + params.flags.clear = TargetBufferFlags::COLOR0; + params.viewport = srcRect; + params.clearColor = math::float4(0.0f, 0.0f, 1.0f, 1.0f); + params.flags.discardStart = TargetBufferFlags::ALL; + params.flags.discardEnd = TargetBufferFlags::NONE; + + PipelineState ps = {}; + ps.program = program; + ps.rasterState.colorWrite = true; + ps.rasterState.depthWrite = false; + ps.scissor = scissor; + + api.makeCurrent(swapChain, swapChain); + api.beginFrame(0, 0); + + api.beginRenderPass(srcRenderTarget, params); + api.draw(ps, triangle.getRenderPrimitive(), 1); + api.endRenderPass(); + + readPixelsAndAssertHash("scissor", kSrcTexWidth >> 1, kSrcTexHeight >> 1, fullRenderTarget, + 0xAB3D1C53, true); + + api.commit(swapChain); + api.endFrame(0); + + api.stopCapture(0); + + // Cleanup. + api.destroyTexture(srcTexture); + api.destroySwapChain(swapChain); + api.destroyRenderTarget(srcRenderTarget); + } + + // Wait for the ReadPixels result to come back. + api.finish(); + + executeCommands(); + getDriver().purge(); +} + +} // namespace test