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 "DoubleBufferedTexture.h"
28
29 #include "ClassTracker.h"
30 #include "GLUtils.h"
31
32 #define LOG_NDEBUG 1
33 #define LOG_TAG "DoubleBufferedTexture.cpp"
34 #include <utils/Log.h>
35
36 namespace WebCore {
37
DoubleBufferedTexture(EGLContext sharedContext,SharedTextureMode mode)38 DoubleBufferedTexture::DoubleBufferedTexture(EGLContext sharedContext, SharedTextureMode mode)
39 {
40 m_sharedTextureMode = mode;
41
42 m_textureA = new SharedTexture(m_sharedTextureMode);
43 if (m_sharedTextureMode == EglImageMode)
44 m_textureB = new SharedTexture(m_sharedTextureMode);
45 else
46 m_textureB = 0;
47
48 m_display = eglGetCurrentDisplay();
49 m_pContext = EGL_NO_CONTEXT;
50 m_cContext = sharedContext;
51 m_writeableTexture = m_textureA;
52 m_lockedConsumerTexture = GL_NO_TEXTURE;
53 m_supportsEGLImage = GLUtils::isEGLImageSupported();
54 #ifdef DEBUG_COUNT
55 ClassTracker::instance()->increment("DoubleBufferedTexture");
56 #endif
57 }
58
~DoubleBufferedTexture()59 DoubleBufferedTexture::~DoubleBufferedTexture()
60 {
61 #ifdef DEBUG_COUNT
62 ClassTracker::instance()->decrement("DoubleBufferedTexture");
63 #endif
64 delete m_textureA;
65 delete m_textureB;
66 }
67
getWriteableTexture()68 SharedTexture* DoubleBufferedTexture::getWriteableTexture()
69 {
70 if (m_sharedTextureMode == SurfaceTextureMode)
71 return m_textureA;
72 return reinterpret_cast<SharedTexture*>(
73 android_atomic_release_load((int32_t*)&m_writeableTexture));
74 }
75
getReadableTexture()76 SharedTexture* DoubleBufferedTexture::getReadableTexture()
77 {
78 if (m_sharedTextureMode == SurfaceTextureMode)
79 return m_textureA;
80 return (getWriteableTexture() != m_textureA) ? m_textureA : m_textureB;
81 }
82
producerAcquireContext()83 EGLContext DoubleBufferedTexture::producerAcquireContext()
84 {
85 if (m_sharedTextureMode == SurfaceTextureMode)
86 return EGL_NO_CONTEXT;
87
88 if (m_pContext != EGL_NO_CONTEXT) {
89 LOGV("AquireContext has previously generated a context.\n");
90 return m_pContext;
91 }
92
93 // check to see if a context already exists on this thread
94 EGLContext context = eglGetCurrentContext();
95
96 // if no context exists then create one
97 if (context == EGL_NO_CONTEXT) {
98 EGLContext sharedContext = m_supportsEGLImage ? EGL_NO_CONTEXT : m_cContext;
99 context = GLUtils::createBackgroundContext(sharedContext);
100 }
101
102 if (context == EGL_NO_CONTEXT) {
103 LOGE("eglCreateContext failed");
104 return EGL_NO_CONTEXT;
105 }
106
107 // initialize the producer's textures
108 m_textureA->lock();
109 if (m_sharedTextureMode == EglImageMode)
110 m_textureB->lock();
111
112 m_textureA->initSourceTexture();
113 LOGV("Initialized Textures A (%d)", m_textureA->getSourceTextureId());
114 if (m_sharedTextureMode == EglImageMode) {
115 m_textureB->initSourceTexture();
116 LOGV("Initialized Textures B (%d)", m_textureB->getSourceTextureId());
117 }
118
119 m_textureA->unlock();
120 if (m_sharedTextureMode == EglImageMode)
121 m_textureB->unlock();
122
123 m_pContext = context;
124 return context;
125 }
126
127 // For MediaTexture only
producerDeleteTextures()128 void DoubleBufferedTexture::producerDeleteTextures()
129 {
130 m_textureA->lock();
131 if (m_sharedTextureMode == EglImageMode)
132 m_textureB->lock();
133
134 LOGV("Deleting Producer Textures A (%d)", m_textureA->getSourceTextureId());
135 m_textureA->deleteSourceTexture();
136 if (m_sharedTextureMode == EglImageMode){
137 LOGV("Deleting Producer Textures B (%d)", m_textureB->getSourceTextureId());
138 m_textureB->deleteSourceTexture();
139 }
140
141 m_textureA->unlock();
142 if (m_sharedTextureMode == EglImageMode)
143 m_textureB->unlock();
144 }
145
146 // For MediaTexture only
consumerDeleteTextures()147 void DoubleBufferedTexture::consumerDeleteTextures()
148 {
149 m_textureA->lock();
150 if (m_sharedTextureMode == EglImageMode)
151 m_textureB->lock();
152
153 LOGV("Deleting Consumer Textures A (%d)", m_textureA->getTargetTextureId());
154 m_textureA->deleteTargetTexture();
155 if (m_sharedTextureMode == EglImageMode) {
156 LOGV("Deleting Consumer Textures B (%d)", m_textureB->getTargetTextureId());
157 m_textureB->deleteTargetTexture();
158 }
159
160 m_textureA->unlock();
161 if (m_sharedTextureMode == EglImageMode)
162 m_textureB->unlock();
163 }
164
producerLock()165 TextureInfo* DoubleBufferedTexture::producerLock()
166 {
167 SharedTexture* sharedTex = getWriteableTexture();
168 LOGV("Acquiring P Lock (%d)", sharedTex->getSourceTextureId());
169 TextureInfo* texInfo = sharedTex->lockSource();
170 LOGV("Acquired P Lock");
171
172 return texInfo;
173 }
174
producerRelease()175 void DoubleBufferedTexture::producerRelease()
176 {
177 // get the writable texture and unlock it
178 SharedTexture* sharedTex = getWriteableTexture();
179 LOGV("Releasing P Lock (%d)", sharedTex->getSourceTextureId());
180 sharedTex->releaseSource();
181 LOGV("Released P Lock (%d)", sharedTex->getSourceTextureId());
182 }
183
producerReleaseAndSwap()184 void DoubleBufferedTexture::producerReleaseAndSwap()
185 {
186 producerRelease();
187 if (m_sharedTextureMode == EglImageMode) {
188 // swap the front and back buffers using an atomic op for the memory barrier
189 android_atomic_acquire_store((int32_t)getReadableTexture(), (int32_t*)&m_writeableTexture);
190 }
191 }
192
consumerLock()193 TextureInfo* DoubleBufferedTexture::consumerLock()
194 {
195 SharedTexture* sharedTex = getReadableTexture();
196 LOGV("Acquiring C Lock (%d)", sharedTex->getSourceTextureId());
197 m_lockedConsumerTexture = sharedTex;
198
199 TextureInfo* texInfo = sharedTex->lockTarget();
200 LOGV("Acquired C Lock");
201
202 if (!texInfo)
203 LOGV("Released C Lock (Empty)");
204
205 return texInfo;
206 }
207
consumerRelease()208 void DoubleBufferedTexture::consumerRelease()
209 {
210 // we must check to see what texture the consumer had locked since the
211 // producer may have swapped out the readable buffer
212 SharedTexture* sharedTex = m_lockedConsumerTexture;
213 sharedTex->releaseTarget();
214 LOGV("Released C Lock (%d)", sharedTex->getSourceTextureId());
215 }
216
217 } // namespace WebCore
218