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