1 /*
2 * Copyright 2010, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "SharedTexture.h"
28
29 #include "GLUtils.h"
30 #include <android/native_window.h>
31 #include <gui/SurfaceTexture.h>
32 #include <gui/SurfaceTextureClient.h>
33
34 #define LOG_NDEBUG 1
35 #define LOG_TAG "SharedTexture.cpp"
36 #include <utils/Log.h>
37
38 namespace WebCore {
39
SharedTexture(SharedTextureMode mode)40 SharedTexture::SharedTexture(SharedTextureMode mode)
41 {
42 m_sharedTextureMode = mode;
43
44 m_sourceTexture = new TextureInfo(m_sharedTextureMode);
45 m_targetTexture = 0;
46
47 if (m_sharedTextureMode == EglImageMode) {
48 m_targetTexture = new TextureInfo(m_sharedTextureMode);
49 m_eglImage = EGL_NO_IMAGE_KHR;
50 m_isNewImage = true;
51 m_syncObject = EGL_NO_SYNC_KHR;
52
53 // Defer initialization of these values until we initialize the source
54 // texture. This ensures that this initialization happens in the appropriate
55 // thread.
56 m_display = 0;
57 m_supportsEGLImage = false;
58 m_supportsEGLFenceSyncKHR = false;
59 } else if (m_sharedTextureMode == SurfaceTextureMode) {
60 #if DEPRECATED_SURFACE_TEXTURE_MODE
61 glGenTextures(1, &m_sourceTexture->m_textureId);
62
63 m_sourceTexture->m_surfaceTexture =
64 new android::SurfaceTexture(m_sourceTexture->m_textureId, false);
65 m_sourceTexture->m_ANW =
66 new android::SurfaceTextureClient(m_sourceTexture->m_surfaceTexture);
67 #endif
68 }
69 }
70
71 // called by the consumer when it no longer wants to consume and after it has
72 // terminated all providers. If EGLImages are used, the deletion of the
73 // source texture and EGLImage is the responsibility of the caller.
~SharedTexture()74 SharedTexture::~SharedTexture()
75 {
76 if (m_sharedTextureMode == EglImageMode)
77 deleteTargetTexture();
78 else if (m_sharedTextureMode == SurfaceTextureMode) {
79 #if DEPRECATED_SURFACE_TEXTURE_MODE
80 m_sourceTexture->m_surfaceTexture.clear();
81 m_sourceTexture->m_ANW.clear();
82 GLUtils::deleteTexture(&m_sourceTexture->m_textureId);
83 #endif
84 }
85 delete m_sourceTexture;
86 delete m_targetTexture;
87 }
88
89
initSourceTexture()90 void SharedTexture::initSourceTexture()
91 {
92 if (m_sharedTextureMode == SurfaceTextureMode)
93 return;
94
95 m_display = eglGetCurrentDisplay();
96 m_supportsEGLImage = GLUtils::isEGLImageSupported();
97 m_supportsEGLFenceSyncKHR = GLUtils::isEGLFenceSyncSupported();
98
99 // TODO temporarily disable fence sync until the EGL framework fixes
100 // performance issues that result from consistently adding/removing fences.
101 m_supportsEGLFenceSyncKHR = false;
102
103 LOGI("imageEGL: %d syncKHR: %d", m_supportsEGLImage, m_supportsEGLFenceSyncKHR);
104
105 glGenTextures(1, &m_sourceTexture->m_textureId);
106
107 }
108
109 // For MediaTexture only
deleteSourceTexture()110 void SharedTexture::deleteSourceTexture()
111 {
112 if (m_sharedTextureMode == SurfaceTextureMode)
113 return;
114 // We need to delete the source texture and EGLImage in the thread in which
115 // it was created. In theory we should be able to delete the EGLImage
116 // from either thread, but it currently throws an error if not deleted
117 // in the same EGLContext from which it was created.
118 if (m_supportsEGLImage) {
119 GLUtils::deleteTexture(&m_sourceTexture->m_textureId);
120 if (m_eglImage != EGL_NO_IMAGE_KHR) {
121 eglDestroyImageKHR(eglGetCurrentDisplay(), m_eglImage);
122 m_eglImage = EGL_NO_IMAGE_KHR;
123 m_isNewImage = true;
124 }
125 LOGI("Deleted Source Texture and EGLImage");
126 }
127 }
128
129 // For MediaTexture only
deleteTargetTexture()130 void SharedTexture::deleteTargetTexture()
131 {
132 if (m_sharedTextureMode == SurfaceTextureMode)
133 return;
134
135 if (m_supportsEGLImage)
136 GLUtils::deleteTexture(&m_targetTexture->m_textureId);
137 else
138 GLUtils::deleteTexture(&m_sourceTexture->m_textureId);
139 }
140
lockSource()141 TextureInfo* SharedTexture::lockSource()
142 {
143 if (m_sharedTextureMode == SurfaceTextureMode)
144 return m_sourceTexture;
145
146 m_lock.lock();
147
148 if (m_supportsEGLFenceSyncKHR && m_syncObject != EGL_NO_SYNC_KHR) {
149
150 EGLint status = eglClientWaitSyncKHR(m_display, m_syncObject, 0, 1000000);
151
152 if (status == EGL_TIMEOUT_EXPIRED_KHR)
153 LOGE("Sync timeout for shared texture (%d)", m_sourceTexture->m_textureId);
154
155 eglDestroySyncKHR(m_display, m_syncObject);
156 m_syncObject = EGL_NO_SYNC_KHR;
157 }
158 return m_sourceTexture;
159 }
160
releaseSource()161 void SharedTexture::releaseSource()
162 {
163 if (m_sharedTextureMode == SurfaceTextureMode)
164 return;
165
166 if (m_supportsEGLImage) {
167 // delete the existing image if needed
168 if (!m_sourceTexture->equalsAttributes(m_targetTexture)) {
169 if (m_eglImage != EGL_NO_IMAGE_KHR) {
170 eglDestroyImageKHR(m_display, m_eglImage);
171 m_eglImage = EGL_NO_IMAGE_KHR;
172 m_isNewImage = true;
173 }
174 m_targetTexture->copyAttributes(m_sourceTexture);
175 }
176
177 // create an image from the texture, only when the texture is valid
178 if (m_eglImage == EGL_NO_IMAGE_KHR && m_sourceTexture->m_width
179 && m_sourceTexture->m_height) {
180 GLUtils::createEGLImageFromTexture(m_sourceTexture->m_textureId, &m_eglImage);
181 LOGV("Generating Image (%d) 0x%x", m_sourceTexture->m_textureId, m_eglImage);
182
183 glFinish(); // ensures the texture is ready to be used by the consumer
184 }
185
186 } else {
187
188 m_targetTexture = m_sourceTexture;
189
190 // in the case of shared contexts we must flush the texture edits to the
191 // GPU. This ensures the edits complete prior to allowing the texture to
192 // be bound on the producers context.
193 glFlush();
194 }
195
196 m_lock.unlock();
197 }
198
lockTarget()199 TextureInfo* SharedTexture::lockTarget()
200 {
201 // Note that the source and targe are the same when using Surface Texture.
202 if (m_sharedTextureMode == SurfaceTextureMode) {
203 #if DEPRECATED_SURFACE_TEXTURE_MODE
204 m_sourceTexture->m_surfaceTexture->updateTexImage();
205 #endif
206 return m_sourceTexture;
207 }
208
209 m_lock.lock();
210
211 if ((!m_supportsEGLImage && m_targetTexture->m_textureId == GL_NO_TEXTURE)
212 || (m_supportsEGLImage && m_eglImage == EGL_NO_IMAGE_KHR)) {
213 m_lock.unlock();
214 return 0;
215 }
216
217 if (m_supportsEGLImage && (m_isNewImage || m_targetTexture->m_textureId == GL_NO_TEXTURE)) {
218 if (m_targetTexture->m_textureId == GL_NO_TEXTURE)
219 glGenTextures(1, &m_targetTexture->m_textureId);
220
221 GLUtils::createTextureFromEGLImage(m_targetTexture->m_textureId, m_eglImage);
222 LOGV("Generating Consumer Texture from 0x%x", m_eglImage);
223 m_isNewImage = false;
224 }
225 return m_targetTexture;
226 }
227
releaseTarget()228 void SharedTexture::releaseTarget()
229 {
230 if (m_sharedTextureMode == SurfaceTextureMode)
231 return;
232
233 if (m_supportsEGLFenceSyncKHR) {
234 if (m_syncObject != EGL_NO_SYNC_KHR)
235 eglDestroySyncKHR(m_display, m_syncObject);
236 m_syncObject = eglCreateSyncKHR(m_display, EGL_SYNC_FENCE_KHR, 0);
237 } else {
238 // TODO the flush currently prevents the screen from getting partial
239 // updates but the only way to guarantee this is to call glFinish. Until
240 // we support an EGL sync we will leave flush enable in order to test
241 // with modest performance.
242 glFlush();
243 }
244
245 m_lock.unlock();
246 }
247
248 } // namespace WebCore
249