// 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 "GLTestUtils.h" #include "OpenGLTestContext.h" #include "TextureDraw.h" namespace gfxstream { namespace gl { namespace { void TestTextureDrawBasic(const GLESv2Dispatch* gl, GLenum internalformat, GLenum format, bool should_work) { GLint viewport[4] = {}; gl->glGetIntegerv(GL_VIEWPORT, viewport); EXPECT_EQ(0, viewport[0]); EXPECT_EQ(0, viewport[1]); const int width = viewport[2]; const int height = viewport[3]; const GLenum type = GL_UNSIGNED_BYTE; const int bpp = 4; const int bytes = width * height * bpp; GLuint textureToDraw; gl->glGenTextures(1, &textureToDraw); gl->glActiveTexture(GL_TEXTURE0); gl->glBindTexture(GL_TEXTURE_2D, textureToDraw); gl->glPixelStorei(GL_PACK_ALIGNMENT, 1); gl->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); std::vector pixels(bytes); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { pixels[i * width * bpp + j * bpp + 0] = (0xaa + i) % 0x100; pixels[i * width * bpp + j * bpp + 1] = (0x00 + j) % 0x100; pixels[i * width * bpp + j * bpp + 2] = (0x11 + i) % 0x100; // Use 0xff for alpha blending. pixels[i * width * bpp + j * bpp + 3] = 0xff; } } GLenum err = gl->glGetError(); EXPECT_EQ(GL_NO_ERROR, err); gl->glTexImage2D(GL_TEXTURE_2D, 0, internalformat, width, height, 0, format, type, pixels.data()); err = gl->glGetError(); if (should_work) { EXPECT_EQ(GL_NO_ERROR, err); } else { EXPECT_NE(GL_NO_ERROR, err); return; } gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); GLint fbStatus = gl->glCheckFramebufferStatus(GL_FRAMEBUFFER); EXPECT_EQ((GLint)GL_FRAMEBUFFER_COMPLETE, fbStatus); TextureDraw textureDraw; textureDraw.draw(textureToDraw, 0, 0, 0); std::vector pixelsOut(bytes, 0xff); gl->glReadPixels(0, 0, width, height, format, type, pixelsOut.data()); // Check that the texture is drawn upside down (because that's what SurfaceFlinger wants) for (int i = 0; i < height; i++) { size_t rowBytes = width * bpp; EXPECT_TRUE(RowMatches(i, width * bpp, pixels.data() + i * rowBytes, pixelsOut.data() + (height - i - 1) * rowBytes)); } } void TestTextureDrawLayer(const GLESv2Dispatch* gl) { GLint viewport[4] = {}; gl->glGetIntegerv(GL_VIEWPORT, viewport); EXPECT_EQ(0, viewport[0]); EXPECT_EQ(0, viewport[1]); const int width = viewport[2]; const int height = viewport[3]; const GLenum type = GL_UNSIGNED_BYTE; const int bpp = 4; const int bytes = width * height * bpp; GLuint textureToDraw; gl->glGenTextures(1, &textureToDraw); gl->glActiveTexture(GL_TEXTURE0); gl->glBindTexture(GL_TEXTURE_2D, textureToDraw); gl->glPixelStorei(GL_PACK_ALIGNMENT, 1); gl->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); std::vector pixels(bytes); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { pixels[i * width * bpp + j * bpp + 0] = 0xff; pixels[i * width * bpp + j * bpp + 1] = 0x0; pixels[i * width * bpp + j * bpp + 2] = 0x0; pixels[i * width * bpp + j * bpp + 3] = 0xff; } } GLenum err = gl->glGetError(); EXPECT_EQ(GL_NO_ERROR, err); gl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, type, pixels.data()); err = gl->glGetError(); EXPECT_EQ(GL_NO_ERROR, err); gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); GLint fbStatus = gl->glCheckFramebufferStatus(GL_FRAMEBUFFER); EXPECT_EQ((GLint)GL_FRAMEBUFFER_COMPLETE, fbStatus); TextureDraw textureDraw; // Test HWC2_COMPOSITION_SOLID_COLOR mode, red color ComposeLayer l = {0, HWC2_COMPOSITION_SOLID_COLOR, {0, 0, width, height}, {0.0, 0.0, (float)width, (float)height}, HWC2_BLEND_MODE_NONE, 1.0, {255, 0, 0, 255}, (hwc_transform_t)0}; textureDraw.prepareForDrawLayer(); textureDraw.drawLayer(l, width, height, width, height, textureToDraw); std::vector pixelsOut(bytes, 0xff); gl->glReadPixels(0, 0, width, height, GL_RGBA, type, pixelsOut.data()); EXPECT_TRUE(ImageMatches(width, height, bpp, width, pixels.data(), pixelsOut.data())); // Test HWC2_COMPOSITION_DEVICE mode, blue texture for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { pixels[i * width * bpp + j * bpp + 0] = 0x0; pixels[i * width * bpp + j * bpp + 1] = 0x0; pixels[i * width * bpp + j * bpp + 2] = 0xff; pixels[i * width * bpp + j * bpp + 3] = 0xff; } } err = gl->glGetError(); EXPECT_EQ(GL_NO_ERROR, err); gl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, type, pixels.data()); l.composeMode = HWC2_COMPOSITION_DEVICE; textureDraw.drawLayer(l, width, height, width, height, textureToDraw); gl->glReadPixels(0, 0, width, height, GL_RGBA, type, pixelsOut.data()); EXPECT_TRUE(ImageMatches(width, height, bpp, width, pixels.data(), pixelsOut.data())); // Test composing 2 layers, layer1 draws blue to the upper half frame; // layer2 draws the bottom half of the texture to the bottom half frame ComposeLayer l1 = {0, HWC2_COMPOSITION_SOLID_COLOR, {0, 0, width, height/2}, {0.0, 0.0, (float)width, (float)height/2}, HWC2_BLEND_MODE_NONE, 1.0, {0, 0, 255, 255}, (hwc_transform_t)0}; ComposeLayer l2 = {0, HWC2_COMPOSITION_DEVICE, {0, height/2, width, height}, {0.0, (float)height/2, (float)width, (float)height}, HWC2_BLEND_MODE_NONE, 1.0, {0, 0, 0, 0}, (hwc_transform_t)0}; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { // texture bottom half green if (i >= height/2) { pixels[i * width * bpp + j * bpp + 0] = 0x0; pixels[i * width * bpp + j * bpp + 2] = 0xff; } } } gl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, type, pixels.data()); textureDraw.drawLayer(l1, width, height, width, height, textureToDraw); textureDraw.drawLayer(l2, width, height, width, height, textureToDraw); gl->glReadPixels(0, 0, width, height, GL_RGBA, type, pixelsOut.data()); EXPECT_TRUE(ImageMatches(width, height, bpp, width, pixels.data(), pixelsOut.data())); } #define GL_BGRA_EXT 0x80E1 TEST_F(GLTest, TextureDrawBasic) { TestTextureDrawBasic(gl, GL_RGBA, GL_RGBA, true); // Assumes BGRA is supported // Note: On NVIDIA EGL, the format mismatch with RGBA cauases a failure. // TestTextureDrawBasic(gl, GL_BGRA_EXT, GL_BGRA_EXT, true); // TestTextureDrawBasic(gl, GL_RGBA, GL_BGRA_EXT, false); TestTextureDrawLayer(gl); } } // namespace } // namespace gl } // namespace gfxstream