1150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph/*
2150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * Copyright (C) 2017 The Android Open Source Project
3150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph *
4150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * Licensed under the Apache License, Version 2.0 (the "License");
5150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * you may not use this file except in compliance with the License.
6150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * You may obtain a copy of the License at
7150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph *
8150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph *      http://www.apache.org/licenses/LICENSE-2.0
9150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph *
10150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * Unless required by applicable law or agreed to in writing, software
11150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * distributed under the License is distributed on an "AS IS" BASIS,
12150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * See the License for the specific language governing permissions and
14150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph * limitations under the License.
15150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph */
16150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
17150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph#include "RenderBase.h"
18150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph#include "glError.h"
19150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
20150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph#include <log/log.h>
21150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph#include <ui/GraphicBuffer.h>
22150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
23150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph// Eventually we shouldn't need this dependency, but for now the
24150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph// graphics allocator interface isn't fully supported on all platforms
25150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph// and this is our work around.
26150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolphusing ::android::GraphicBuffer;
27150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
28150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
29150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph// OpenGL state shared among all renderers
30150c580464a7a4d6b0ad3362f23f790ded65e7abScott RandolphEGLDisplay   RenderBase::sDisplay = EGL_NO_DISPLAY;
31150c580464a7a4d6b0ad3362f23f790ded65e7abScott RandolphEGLContext   RenderBase::sContext = EGL_NO_CONTEXT;
32150c580464a7a4d6b0ad3362f23f790ded65e7abScott RandolphEGLSurface   RenderBase::sDummySurface = EGL_NO_SURFACE;
33150c580464a7a4d6b0ad3362f23f790ded65e7abScott RandolphGLuint       RenderBase::sFrameBuffer = -1;
34150c580464a7a4d6b0ad3362f23f790ded65e7abScott RandolphGLuint       RenderBase::sColorBuffer = -1;
35150c580464a7a4d6b0ad3362f23f790ded65e7abScott RandolphGLuint       RenderBase::sDepthBuffer = -1;
36150c580464a7a4d6b0ad3362f23f790ded65e7abScott RandolphEGLImageKHR  RenderBase::sKHRimage = EGL_NO_IMAGE_KHR;
37150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolphunsigned     RenderBase::sWidth  = 0;
38150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolphunsigned     RenderBase::sHeight = 0;
394a83b5dba29eceaf43c4ff7d5c184463949174ccScott Randolphfloat        RenderBase::sAspectRatio = 0.0f;
40150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
41150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
42150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolphbool RenderBase::prepareGL() {
43150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Just trivially return success if we're already prepared
44150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (sDisplay != EGL_NO_DISPLAY) {
45150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return true;
46150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
47150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
48150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Hardcoded to RGBx output display
49150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    const EGLint config_attribs[] = {
50150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        // Tag                  Value
51150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
52150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        EGL_RED_SIZE,           8,
53150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        EGL_GREEN_SIZE,         8,
54150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        EGL_BLUE_SIZE,          8,
55150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        EGL_NONE
56150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    };
57150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
58150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Select OpenGL ES v 3
59150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
60150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
61150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
62150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Set up our OpenGL ES context associated with the default display (though we won't be visible)
63150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
64150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (display == EGL_NO_DISPLAY) {
65150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGE("Failed to get egl display");
66150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return false;
67150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
68150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
69150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    EGLint major = 0;
70150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    EGLint minor = 0;
71150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (!eglInitialize(display, &major, &minor)) {
72150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGE("Failed to initialize EGL: %s", getEGLError());
73150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return false;
74150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    } else {
75150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGI("Intiialized EGL at %d.%d", major, minor);
76150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
77150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
78150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
79150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Select the configuration that "best" matches our desired characteristics
80150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    EGLConfig egl_config;
81150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    EGLint num_configs;
82150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (!eglChooseConfig(display, config_attribs, &egl_config, 1, &num_configs)) {
83150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGE("eglChooseConfig() failed with error: %s", getEGLError());
84150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return false;
85150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
86150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
87150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
88150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Create a dummy pbuffer so we have a surface to bind -- we never intend to draw to this
89150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // because attachRenderTarget will be called first.
90150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    EGLint surface_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
91150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    sDummySurface = eglCreatePbufferSurface(display, egl_config, surface_attribs);
92150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (sDummySurface == EGL_NO_SURFACE) {
93150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGE("Failed to create OpenGL ES Dummy surface: %s", getEGLError());
94150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return false;
95150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    } else {
96150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGI("Dummy surface looks good!  :)");
97150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
98150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
99150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
100150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    //
101150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Create the EGL context
102150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    //
103150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    EGLContext context = eglCreateContext(display, egl_config, EGL_NO_CONTEXT, context_attribs);
104150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (context == EGL_NO_CONTEXT) {
105150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGE("Failed to create OpenGL ES Context: %s", getEGLError());
106150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return false;
107150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
108150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
109150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
110150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Activate our render target for drawing
111150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (!eglMakeCurrent(display, sDummySurface, sDummySurface, context)) {
112150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGE("Failed to make the OpenGL ES Context current: %s", getEGLError());
113150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return false;
114150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    } else {
115150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGI("We made our context current!  :)");
116150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
117150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
118150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
119150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Report the extensions available on this implementation
120150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    const char* gl_extensions = (const char*) glGetString(GL_EXTENSIONS);
121150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    ALOGI("GL EXTENSIONS:\n  %s", gl_extensions);
122150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
123150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
124150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Reserve handles for the color and depth targets we'll be setting up
125150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    glGenRenderbuffers(1, &sColorBuffer);
126150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    glGenRenderbuffers(1, &sDepthBuffer);
127150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
128150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Set up the frame buffer object we can modify and use for off screen rendering
129150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    glGenFramebuffers(1, &sFrameBuffer);
130150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    glBindFramebuffer(GL_FRAMEBUFFER, sFrameBuffer);
131150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
132150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
133150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Now that we're assured success, store object handles we constructed
134150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    sDisplay = display;
135150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    sContext = context;
136150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
137150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    return true;
138150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph}
139150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
140150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
141150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolphbool RenderBase::attachRenderTarget(const BufferDesc& tgtBuffer) {
142150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Hardcoded to RGBx for now
143150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (tgtBuffer.format != HAL_PIXEL_FORMAT_RGBA_8888) {
144150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGE("Unsupported target buffer format");
145150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return false;
146150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
147150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
148150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // create a GraphicBuffer from the existing handle
149150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    sp<GraphicBuffer> pGfxBuffer = new GraphicBuffer(tgtBuffer.memHandle,
150150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                                                     GraphicBuffer::CLONE_HANDLE,
151150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                                                     tgtBuffer.width, tgtBuffer.height,
152150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                                                     tgtBuffer.format, 1, // layer count
153150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                                                     GRALLOC_USAGE_HW_RENDER,
154150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                                                     tgtBuffer.stride);
155150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (pGfxBuffer.get() == nullptr) {
156150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
157150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return false;
158150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
159150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
160150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Get a GL compatible reference to the graphics buffer we've been given
161150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
162150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    EGLClientBuffer clientBuf = static_cast<EGLClientBuffer>(pGfxBuffer->getNativeBuffer());
163150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    sKHRimage = eglCreateImageKHR(sDisplay, EGL_NO_CONTEXT,
164150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                                  EGL_NATIVE_BUFFER_ANDROID, clientBuf,
165150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph                                  eglImageAttributes);
166150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (sKHRimage == EGL_NO_IMAGE_KHR) {
167150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGE("error creating EGLImage for target buffer: %s", getEGLError());
168150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return false;
169150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
170150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
171150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Construct a render buffer around the external buffer
172150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    glBindRenderbuffer(GL_RENDERBUFFER, sColorBuffer);
173150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, static_cast<GLeglImageOES>(sKHRimage));
174150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (eglGetError() != EGL_SUCCESS) {
175150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGI("glEGLImageTargetRenderbufferStorageOES => %s", getEGLError());
176150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return false;
177150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
178150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
179150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, sColorBuffer);
180150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (eglGetError() != EGL_SUCCESS) {
181150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGE("glFramebufferRenderbuffer => %s", getEGLError());
182150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return false;
183150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
184150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
185150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    GLenum checkResult = glCheckFramebufferStatus(GL_FRAMEBUFFER);
186150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (checkResult != GL_FRAMEBUFFER_COMPLETE) {
187150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        ALOGE("Offscreen framebuffer not configured successfully (%d: %s)",
188150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph              checkResult, getGLFramebufferError());
189150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        return false;
190150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
191150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
1924a83b5dba29eceaf43c4ff7d5c184463949174ccScott Randolph    // Store the size of our target buffer
1934a83b5dba29eceaf43c4ff7d5c184463949174ccScott Randolph    sWidth = tgtBuffer.width;
1944a83b5dba29eceaf43c4ff7d5c184463949174ccScott Randolph    sHeight = tgtBuffer.height;
1954a83b5dba29eceaf43c4ff7d5c184463949174ccScott Randolph    sAspectRatio = (float)sWidth / sHeight;
1964a83b5dba29eceaf43c4ff7d5c184463949174ccScott Randolph
1974a83b5dba29eceaf43c4ff7d5c184463949174ccScott Randolph    // Set the viewport
1984a83b5dba29eceaf43c4ff7d5c184463949174ccScott Randolph    glViewport(0, 0, sWidth, sHeight);
1994a83b5dba29eceaf43c4ff7d5c184463949174ccScott Randolph
2004a83b5dba29eceaf43c4ff7d5c184463949174ccScott Randolph#if 1   // We don't actually need the clear if we're going to cover the whole screen anyway
2014a83b5dba29eceaf43c4ff7d5c184463949174ccScott Randolph    // Clear the color buffer
2024a83b5dba29eceaf43c4ff7d5c184463949174ccScott Randolph    glClearColor(0.8f, 0.1f, 0.2f, 1.0f);
2034a83b5dba29eceaf43c4ff7d5c184463949174ccScott Randolph    glClear(GL_COLOR_BUFFER_BIT);
2044a83b5dba29eceaf43c4ff7d5c184463949174ccScott Randolph#endif
2054a83b5dba29eceaf43c4ff7d5c184463949174ccScott Randolph
2064a83b5dba29eceaf43c4ff7d5c184463949174ccScott Randolph
207150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    return true;
208150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph}
209150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
210150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph
211150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolphvoid RenderBase::detachRenderTarget() {
212150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    // Drop our external render target
213150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    if (sKHRimage != EGL_NO_IMAGE_KHR) {
214150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        eglDestroyImageKHR(sDisplay, sKHRimage);
215150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph        sKHRimage = EGL_NO_IMAGE_KHR;
216150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph    }
217150c580464a7a4d6b0ad3362f23f790ded65e7abScott Randolph}