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