• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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