// Copyright (C) 2018 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 #include "host-common/testing/MockGraphicsAgentFactory.h" #include "Standalone.h" #include "GLTestUtils.h" #include namespace gfxstream { namespace { using gl::GLESApi; using gl::GLESApi_2; using gl::GLESApi_3_0; using gl::GLESApi_3_1; using gl::GLESApi_3_2; using gl::GLESApi_CM; using gl::LazyLoadedEGLDispatch; using gl::LazyLoadedGLESv2Dispatch; struct ClearColorParam { const GLESApi glVersion; const bool fastBlit; ClearColorParam(GLESApi glVersion, bool fastBlit) : glVersion(glVersion), fastBlit(fastBlit) {} }; static void PrintTo(const ClearColorParam& param, std::ostream* os) { *os << "ClearColorParam("; switch (param.glVersion) { case GLESApi_CM: *os << "GLESApi_CM"; break; case GLESApi_2: *os << "GLESApi_2"; break; case GLESApi_3_0: *os << "GLESApi_3_0"; break; case GLESApi_3_1: *os << "GLESApi_3_1"; break; case GLESApi_3_2: *os << "GLESApi_3_2"; break; default: *os << "GLESApi(" << int(param.glVersion) << ")"; break; } *os << ", " << (param.fastBlit ? "fast blit" : "slow blit") << ")"; } class ClearColor final : public SampleApplication { public: ClearColor(ClearColorParam param) : SampleApplication(256, 256, 60, param.glVersion) { if (!param.fastBlit) { // Disable fast blit and then recreate the color buffer to apply the // change. mFb->disableFastBlitForTesting(); mFb->closeColorBuffer(mColorBuffer); mColorBuffer = mFb->createColorBuffer( mWidth, mHeight, GL_RGBA, FRAMEWORK_FORMAT_GL_COMPATIBLE); mFb->setEmulatedEglWindowSurfaceColorBuffer(mSurface, mColorBuffer); } } ~ClearColor() { auto gl = LazyLoadedGLESv2Dispatch::get(); if (mFbo) { gl->glDeleteFramebuffers(1, &mFbo); gl->glDeleteTextures(1, &mTexture); } } void setClearColor(float r, float g, float b, float a) { mRed = r; mGreen = g; mBlue = b; mAlpha = a; } void setUseFboCombined(bool useFbo) { mUseFboCombined = useFbo; } void setUseFbo(bool useFboDraw, bool useFboRead) { mUseFboDraw = useFboDraw; mUseFboRead = useFboRead; } void initialize() override { auto gl = LazyLoadedGLESv2Dispatch::get(); gl->glActiveTexture(GL_TEXTURE0); if (!mFbo) { gl->glGenFramebuffers(1, &mFbo); gl->glGenTextures(1, &mTexture); gl->glBindTexture(GL_TEXTURE_2D, mTexture); gl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); gl->glBindTexture(GL_TEXTURE_2D, 0); gl->glBindFramebuffer(GL_FRAMEBUFFER, mFbo); gl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0); gl->glBindFramebuffer(GL_FRAMEBUFFER, 0); } } void draw() override { auto gl = LazyLoadedGLESv2Dispatch::get(); gl->glBindFramebuffer(GL_FRAMEBUFFER, mUseFboCombined ? mFbo : 0); if (mUseFboDraw) { gl->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFbo); } if (mUseFboRead) { gl->glBindFramebuffer(GL_READ_FRAMEBUFFER, mFbo); } gl->glClearColor(mRed, mGreen, mBlue, mAlpha); gl->glClear(GL_COLOR_BUFFER_BIT); } void setNonDefaultCombinedFbo() { setUseFboCombined(true); } void setNonDefaultDrawFbo() { setUseFbo(true, mUseFboRead); } void setNonDefaultReadFbo() { setUseFbo(mUseFboDraw, true); } void drawWithColor(const float drawColor[4]) { setClearColor(drawColor[0], drawColor[1], drawColor[2], drawColor[3]); drawOnce(); } void verifySwappedColor(const float wantedColor[4]) { TestTexture targetBuffer = createTestTextureRGBA8888SingleColor( mWidth, mHeight, wantedColor[0], wantedColor[1], wantedColor[2], wantedColor[3]); TestTexture forRead = createTestTextureRGBA8888SingleColor( mWidth, mHeight, 0.0f, 0.0f, 0.0f, 0.0f); mFb->readColorBuffer( mColorBuffer, 0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, forRead.data()); EXPECT_TRUE( ImageMatches(mWidth, mHeight, 4, mWidth, targetBuffer.data(), forRead.data())); } private: bool mUseFboCombined = false; bool mUseFboDraw = false; bool mUseFboRead = false; GLuint mFbo = 0; GLuint mTexture = 0; float mRed = 1.0f; float mGreen = 1.0f; float mBlue = 1.0f; float mAlpha = 1.0f; }; static constexpr float kDrawColorRed[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; static constexpr float kDrawColorGreen[4] = { 0.0f, 1.0f, 0.0f, 1.0f }; class CombinedFramebufferBlit : public ::testing::Test, public ::testing::WithParamInterface { protected: static void SetUpTestSuite() { android::emulation::injectGraphicsAgents( android::emulation::MockGraphicsAgentFactory()); } static void TearDownTestSuite() { } virtual void SetUp() override { mApp.reset(new ClearColor(GetParam())); } virtual void TearDown() override { mApp.reset(); EXPECT_EQ(EGL_SUCCESS, LazyLoadedEGLDispatch::get()->eglGetError()) << "DefaultFramebufferBlitTest TearDown found an EGL error"; } std::unique_ptr mApp; }; TEST_P(CombinedFramebufferBlit, DefaultDrawDefaultRead) { // Draw to default framebuffer; color should show up mApp->drawWithColor(kDrawColorRed); mApp->verifySwappedColor(kDrawColorRed); } TEST_P(CombinedFramebufferBlit, NonDefault) { mApp->drawWithColor(kDrawColorRed); mApp->verifySwappedColor(kDrawColorRed); // Color should not be affected by the draw to a non-default framebuffer. mApp->setNonDefaultCombinedFbo(); mApp->drawWithColor(kDrawColorGreen); mApp->verifySwappedColor(kDrawColorRed); } // Test blitting both with only the fast blit path. INSTANTIATE_TEST_SUITE_P(CombinedFramebufferBlitTest, CombinedFramebufferBlit, testing::Values( ClearColorParam(GLESApi_CM, true), ClearColorParam(GLESApi_2, true), ClearColorParam(GLESApi_3_0, true))); class NonDefaultFramebufferBlit : public CombinedFramebufferBlit { }; TEST_P(NonDefaultFramebufferBlit, NonDefaultDrawNonDefaultRead) { mApp->drawWithColor(kDrawColorRed); mApp->verifySwappedColor(kDrawColorRed); // Color should not be affected by the draw to non-default // draw/read framebuffers. // (we preserve the previous contents of the surface in // SampleApplication::drawOnce) mApp->setNonDefaultDrawFbo(); mApp->setNonDefaultReadFbo(); mApp->drawWithColor(kDrawColorGreen); mApp->verifySwappedColor(kDrawColorRed); } TEST_P(NonDefaultFramebufferBlit, DefaultDrawNonDefaultRead) { mApp->drawWithColor(kDrawColorRed); mApp->verifySwappedColor(kDrawColorRed); // Bug: 110996998 // Draw to default framebuffer, and have a non-default // read framebuffer bound. Color should show up mApp->setNonDefaultReadFbo(); mApp->drawWithColor(kDrawColorGreen); mApp->verifySwappedColor(kDrawColorGreen); } TEST_P(NonDefaultFramebufferBlit, NonDefaultDrawDefaultRead) { mApp->drawWithColor(kDrawColorRed); mApp->verifySwappedColor(kDrawColorRed); // Draw to non-default framebuffer, and have the default // read framebuffer bound. Color should not show up. // (we preserve the previous contents of the surface in // SampleApplication::drawOnce) mApp->setNonDefaultDrawFbo(); mApp->drawWithColor(kDrawColorGreen); mApp->verifySwappedColor(kDrawColorRed); } // Test blitting both with and without the fast blit path. INSTANTIATE_TEST_SUITE_P(DefaultFramebufferBlitTest, NonDefaultFramebufferBlit, testing::Values( ClearColorParam(GLESApi_3_0, true))); } // namespace } // namespace gfxstream