1/* 2 * Copyright 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#undef LOG_TAG 19#define LOG_TAG "RenderEngine" 20#define ATRACE_TAG ATRACE_TAG_GRAPHICS 21 22#include <GLES2/gl2.h> 23#include <GLES2/gl2ext.h> 24 25#include <ui/ColorSpace.h> 26#include <ui/DebugUtils.h> 27#include <ui/Rect.h> 28 29#include <utils/String8.h> 30#include <utils/Trace.h> 31 32#include <cutils/compiler.h> 33#include <gui/ISurfaceComposer.h> 34#include <math.h> 35 36#include "GLES20RenderEngine.h" 37#include "Program.h" 38#include "ProgramCache.h" 39#include "Description.h" 40#include "Mesh.h" 41#include "Texture.h" 42 43#include <sstream> 44#include <fstream> 45 46// --------------------------------------------------------------------------- 47#ifdef USE_HWC2 48bool checkGlError(const char* op, int lineNumber) { 49 bool errorFound = false; 50 GLint error = glGetError(); 51 while (error != GL_NO_ERROR) { 52 errorFound = true; 53 error = glGetError(); 54 ALOGV("after %s() (line # %d) glError (0x%x)\n", op, lineNumber, error); 55 } 56 return errorFound; 57} 58 59static constexpr bool outputDebugPPMs = false; 60 61void writePPM(const char* basename, GLuint width, GLuint height) { 62 ALOGV("writePPM #%s: %d x %d", basename, width, height); 63 64 std::vector<GLubyte> pixels(width * height * 4); 65 std::vector<GLubyte> outBuffer(width * height * 3); 66 67 // TODO(courtneygo): We can now have float formats, need 68 // to remove this code or update to support. 69 // Make returned pixels fit in uint32_t, one byte per component 70 glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); 71 if (checkGlError(__FUNCTION__, __LINE__)) { 72 return; 73 } 74 75 std::string filename(basename); 76 filename.append(".ppm"); 77 std::ofstream file(filename.c_str(), std::ios::binary); 78 if (!file.is_open()) { 79 ALOGE("Unable to open file: %s", filename.c_str()); 80 ALOGE("You may need to do: \"adb shell setenforce 0\" to enable " 81 "surfaceflinger to write debug images"); 82 return; 83 } 84 85 file << "P6\n"; 86 file << width << "\n"; 87 file << height << "\n"; 88 file << 255 << "\n"; 89 90 auto ptr = reinterpret_cast<char*>(pixels.data()); 91 auto outPtr = reinterpret_cast<char*>(outBuffer.data()); 92 for (int y = height - 1; y >= 0; y--) { 93 char* data = ptr + y * width * sizeof(uint32_t); 94 95 for (GLuint x = 0; x < width; x++) { 96 // Only copy R, G and B components 97 outPtr[0] = data[0]; 98 outPtr[1] = data[1]; 99 outPtr[2] = data[2]; 100 data += sizeof(uint32_t); 101 outPtr += 3; 102 } 103 } 104 file.write(reinterpret_cast<char*>(outBuffer.data()), outBuffer.size()); 105} 106#endif 107 108// --------------------------------------------------------------------------- 109namespace android { 110// --------------------------------------------------------------------------- 111 112GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags) : 113 mVpWidth(0), 114 mVpHeight(0), 115 mPlatformHasWideColor((featureFlags & WIDE_COLOR_SUPPORT) != 0) { 116 117 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); 118 glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); 119 120 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); 121 glPixelStorei(GL_PACK_ALIGNMENT, 4); 122 123 const uint16_t protTexData[] = { 0 }; 124 glGenTextures(1, &mProtectedTexName); 125 glBindTexture(GL_TEXTURE_2D, mProtectedTexName); 126 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 127 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 128 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 129 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 130 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, 131 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData); 132 133 //mColorBlindnessCorrection = M; 134 135#ifdef USE_HWC2 136 if (mPlatformHasWideColor) { 137 // Compute sRGB to DisplayP3 color transform 138 // NOTE: For now, we are limiting wide-color support to 139 // Display-P3 only. 140 mat3 srgbToP3 = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::DisplayP3()).getTransform(); 141 142 // color transform needs to be expanded to 4x4 to be what the shader wants 143 // mat has an initializer that expands mat3 to mat4, but 144 // not an assignment operator 145 mat4 gamutTransform(srgbToP3); 146 mSrgbToDisplayP3 = gamutTransform; 147 } 148#endif 149} 150 151GLES20RenderEngine::~GLES20RenderEngine() { 152} 153 154 155size_t GLES20RenderEngine::getMaxTextureSize() const { 156 return mMaxTextureSize; 157} 158 159size_t GLES20RenderEngine::getMaxViewportDims() const { 160 return 161 mMaxViewportDims[0] < mMaxViewportDims[1] ? 162 mMaxViewportDims[0] : mMaxViewportDims[1]; 163} 164 165void GLES20RenderEngine::setViewportAndProjection( 166 size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, bool yswap, 167 Transform::orientation_flags rotation) { 168 169 size_t l = sourceCrop.left; 170 size_t r = sourceCrop.right; 171 172 // In GL, (0, 0) is the bottom-left corner, so flip y coordinates 173 size_t t = hwh - sourceCrop.top; 174 size_t b = hwh - sourceCrop.bottom; 175 176 mat4 m; 177 if (yswap) { 178 m = mat4::ortho(l, r, t, b, 0, 1); 179 } else { 180 m = mat4::ortho(l, r, b, t, 0, 1); 181 } 182 183 // Apply custom rotation to the projection. 184 float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f; 185 switch (rotation) { 186 case Transform::ROT_0: 187 break; 188 case Transform::ROT_90: 189 m = mat4::rotate(rot90InRadians, vec3(0,0,1)) * m; 190 break; 191 case Transform::ROT_180: 192 m = mat4::rotate(rot90InRadians * 2.0f, vec3(0,0,1)) * m; 193 break; 194 case Transform::ROT_270: 195 m = mat4::rotate(rot90InRadians * 3.0f, vec3(0,0,1)) * m; 196 break; 197 default: 198 break; 199 } 200 201 glViewport(0, 0, vpw, vph); 202 mState.setProjectionMatrix(m); 203 mVpWidth = vpw; 204 mVpHeight = vph; 205} 206 207#ifdef USE_HWC2 208void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha, 209 bool opaque, float alpha) { 210#else 211void GLES20RenderEngine::setupLayerBlending( 212 bool premultipliedAlpha, bool opaque, int alpha) { 213#endif 214 215 mState.setPremultipliedAlpha(premultipliedAlpha); 216 mState.setOpaque(opaque); 217#ifdef USE_HWC2 218 mState.setPlaneAlpha(alpha); 219 220 if (alpha < 1.0f || !opaque) { 221#else 222 mState.setPlaneAlpha(alpha / 255.0f); 223 224 if (alpha < 0xFF || !opaque) { 225#endif 226 glEnable(GL_BLEND); 227 glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 228 } else { 229 glDisable(GL_BLEND); 230 } 231} 232 233#ifdef USE_HWC2 234void GLES20RenderEngine::setupDimLayerBlending(float alpha) { 235#else 236void GLES20RenderEngine::setupDimLayerBlending(int alpha) { 237#endif 238 mState.setPlaneAlpha(1.0f); 239 mState.setPremultipliedAlpha(true); 240 mState.setOpaque(false); 241#ifdef USE_HWC2 242 mState.setColor(0, 0, 0, alpha); 243#else 244 mState.setColor(0, 0, 0, alpha/255.0f); 245#endif 246 mState.disableTexture(); 247 248#ifdef USE_HWC2 249 if (alpha == 1.0f) { 250#else 251 if (alpha == 0xFF) { 252#endif 253 glDisable(GL_BLEND); 254 } else { 255 glEnable(GL_BLEND); 256 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 257 } 258} 259 260#ifdef USE_HWC2 261void GLES20RenderEngine::setColorMode(android_color_mode mode) { 262 ALOGV("setColorMode: %s (0x%x)", decodeColorMode(mode).c_str(), mode); 263 264 if (mColorMode == mode) return; 265 266 if (!mPlatformHasWideColor || !mDisplayHasWideColor || mode == HAL_COLOR_MODE_SRGB || 267 mode == HAL_COLOR_MODE_NATIVE) { 268 // We are returning back to our default color_mode 269 mUseWideColor = false; 270 mWideColorFrameCount = 0; 271 } else { 272 mUseWideColor = true; 273 } 274 275 mColorMode = mode; 276} 277 278void GLES20RenderEngine::setSourceDataSpace(android_dataspace source) { 279 if (source == HAL_DATASPACE_UNKNOWN) { 280 // Treat UNKNOWN as SRGB 281 source = HAL_DATASPACE_V0_SRGB; 282 } 283 mDataSpace = source; 284} 285 286void GLES20RenderEngine::setWideColor(bool hasWideColor) { 287 ALOGV("setWideColor: %s", hasWideColor ? "true" : "false"); 288 mDisplayHasWideColor = hasWideColor; 289} 290 291bool GLES20RenderEngine::usesWideColor() { 292 return mUseWideColor; 293} 294#endif 295 296void GLES20RenderEngine::setupLayerTexturing(const Texture& texture) { 297 GLuint target = texture.getTextureTarget(); 298 glBindTexture(target, texture.getTextureName()); 299 GLenum filter = GL_NEAREST; 300 if (texture.getFiltering()) { 301 filter = GL_LINEAR; 302 } 303 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 304 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 305 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter); 306 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter); 307 308 mState.setTexture(texture); 309} 310 311void GLES20RenderEngine::setupLayerBlackedOut() { 312 glBindTexture(GL_TEXTURE_2D, mProtectedTexName); 313 Texture texture(Texture::TEXTURE_2D, mProtectedTexName); 314 texture.setDimensions(1, 1); // FIXME: we should get that from somewhere 315 mState.setTexture(texture); 316} 317 318mat4 GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) { 319 mat4 oldTransform = mState.getColorMatrix(); 320 mState.setColorMatrix(colorTransform); 321 return oldTransform; 322} 323 324void GLES20RenderEngine::disableTexturing() { 325 mState.disableTexture(); 326} 327 328void GLES20RenderEngine::disableBlending() { 329 glDisable(GL_BLEND); 330} 331 332 333void GLES20RenderEngine::bindImageAsFramebuffer(EGLImageKHR image, 334 uint32_t* texName, uint32_t* fbName, uint32_t* status) { 335 GLuint tname, name; 336 // turn our EGLImage into a texture 337 glGenTextures(1, &tname); 338 glBindTexture(GL_TEXTURE_2D, tname); 339 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); 340 341 // create a Framebuffer Object to render into 342 glGenFramebuffers(1, &name); 343 glBindFramebuffer(GL_FRAMEBUFFER, name); 344 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0); 345 346 *status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 347 *texName = tname; 348 *fbName = name; 349} 350 351void GLES20RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName) { 352 glBindFramebuffer(GL_FRAMEBUFFER, 0); 353 glDeleteFramebuffers(1, &fbName); 354 glDeleteTextures(1, &texName); 355} 356 357void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) { 358 mState.setPlaneAlpha(1.0f); 359 mState.setPremultipliedAlpha(true); 360 mState.setOpaque(false); 361 mState.setColor(r, g, b, a); 362 mState.disableTexture(); 363 glDisable(GL_BLEND); 364} 365 366void GLES20RenderEngine::drawMesh(const Mesh& mesh) { 367 368 if (mesh.getTexCoordsSize()) { 369 glEnableVertexAttribArray(Program::texCoords); 370 glVertexAttribPointer(Program::texCoords, 371 mesh.getTexCoordsSize(), 372 GL_FLOAT, GL_FALSE, 373 mesh.getByteStride(), 374 mesh.getTexCoords()); 375 } 376 377 glVertexAttribPointer(Program::position, 378 mesh.getVertexSize(), 379 GL_FLOAT, GL_FALSE, 380 mesh.getByteStride(), 381 mesh.getPositions()); 382 383#ifdef USE_HWC2 384 if (usesWideColor()) { 385 Description wideColorState = mState; 386 if (mDataSpace != HAL_DATASPACE_DISPLAY_P3) { 387 wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3); 388 wideColorState.setWideGamut(true); 389 ALOGV("drawMesh: gamut transform applied"); 390 } 391 ProgramCache::getInstance().useProgram(wideColorState); 392 393 glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount()); 394 395 if (outputDebugPPMs) { 396 std::ostringstream out; 397 out << "/data/texture_out" << mWideColorFrameCount++; 398 writePPM(out.str().c_str(), mVpWidth, mVpHeight); 399 } 400 } else { 401 ProgramCache::getInstance().useProgram(mState); 402 403 glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount()); 404 } 405#else 406 ProgramCache::getInstance().useProgram(mState); 407 408 glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount()); 409#endif 410 411 if (mesh.getTexCoordsSize()) { 412 glDisableVertexAttribArray(Program::texCoords); 413 } 414} 415 416void GLES20RenderEngine::dump(String8& result) { 417 RenderEngine::dump(result); 418#ifdef USE_HWC2 419 if (usesWideColor()) { 420 result.append("Wide-color: On\n"); 421 } else { 422 result.append("Wide-color: Off\n"); 423 } 424#endif 425} 426 427// --------------------------------------------------------------------------- 428}; // namespace android 429// --------------------------------------------------------------------------- 430 431#if defined(__gl_h_) 432#error "don't include gl/gl.h in this file" 433#endif 434