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