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