blob: 479d8038891b20ac3aa59d420739ce6007edd47c [file] [log] [blame]
Jamie Gennis8ba32fa2010-12-20 11:27:26 -08001/*
2 * Copyright (C) 2010 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_TAG "SurfaceTexture"
18
19#define GL_GLEXT_PROTOTYPES
20#define EGL_EGLEXT_PROTOTYPES
21
22#include <EGL/egl.h>
23#include <EGL/eglext.h>
24#include <GLES2/gl2.h>
25#include <GLES2/gl2ext.h>
26
27#include <gui/SurfaceTexture.h>
28
29#include <surfaceflinger/ISurfaceComposer.h>
30#include <surfaceflinger/SurfaceComposerClient.h>
31
32#include <utils/Log.h>
33
34namespace android {
35
36SurfaceTexture::SurfaceTexture(GLuint tex) :
37 mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT),
38 mLastQueued(INVALID_BUFFER_SLOT), mTexName(tex) {
Jamie Gennis3461e0f2011-01-07 16:05:47 -080039 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
40 mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
41 mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
42 mSlots[i].mOwnedByClient = false;
43 }
Jamie Gennis8ba32fa2010-12-20 11:27:26 -080044}
45
46SurfaceTexture::~SurfaceTexture() {
47 freeAllBuffers();
48}
49
50status_t SurfaceTexture::setBufferCount(int bufferCount) {
51 Mutex::Autolock lock(mMutex);
52 freeAllBuffers();
53 mBufferCount = bufferCount;
54 return OK;
55}
56
57sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf,
58 uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
59 Mutex::Autolock lock(mMutex);
60 if (buf < 0 || mBufferCount <= buf) {
61 LOGE("requestBuffer: slot index out of range [0, %d]: %d",
62 mBufferCount, buf);
63 return 0;
64 }
65 usage |= GraphicBuffer::USAGE_HW_TEXTURE;
66 sp<ISurfaceComposer> composer(ComposerService::getComposerService());
67 sp<GraphicBuffer> graphicBuffer(composer->createGraphicBuffer(w, h,
68 format, usage));
69 if (graphicBuffer == 0) {
70 LOGE("requestBuffer: SurfaceComposer::createGraphicBuffer failed");
71 } else {
72 mSlots[buf].mGraphicBuffer = graphicBuffer;
73 if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
74 eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage);
75 mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
76 mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
77 }
78 }
79 return graphicBuffer;
80}
81
82status_t SurfaceTexture::dequeueBuffer(int *buf) {
83 Mutex::Autolock lock(mMutex);
84 int found = INVALID_BUFFER_SLOT;
85 for (int i = 0; i < mBufferCount; i++) {
86 if (!mSlots[i].mOwnedByClient && i != mCurrentTexture) {
87 mSlots[i].mOwnedByClient = true;
88 found = i;
89 break;
90 }
91 }
92 if (found == INVALID_BUFFER_SLOT) {
93 return -EBUSY;
94 }
95 *buf = found;
96 return OK;
97}
98
99status_t SurfaceTexture::queueBuffer(int buf) {
100 Mutex::Autolock lock(mMutex);
101 if (buf < 0 || mBufferCount <= buf) {
102 LOGE("queueBuffer: slot index out of range [0, %d]: %d",
103 mBufferCount, buf);
104 return -EINVAL;
105 } else if (!mSlots[buf].mOwnedByClient) {
106 LOGE("queueBuffer: slot %d is not owned by the client", buf);
107 return -EINVAL;
108 } else if (mSlots[buf].mGraphicBuffer == 0) {
109 LOGE("queueBuffer: slot %d was enqueued without requesting a buffer",
110 buf);
111 return -EINVAL;
112 }
113 mSlots[buf].mOwnedByClient = false;
114 mLastQueued = buf;
115 return OK;
116}
117
118void SurfaceTexture::cancelBuffer(int buf) {
119 Mutex::Autolock lock(mMutex);
120 if (buf < 0 || mBufferCount <= buf) {
121 LOGE("cancelBuffer: slot index out of range [0, %d]: %d", mBufferCount,
122 buf);
123 return;
124 } else if (!mSlots[buf].mOwnedByClient) {
125 LOGE("cancelBuffer: slot %d is not owned by the client", buf);
126 return;
127 }
128 mSlots[buf].mOwnedByClient = false;
129}
130
131status_t SurfaceTexture::setCrop(const Rect& reg) {
132 Mutex::Autolock lock(mMutex);
133 // XXX: How should we handle crops?
134 return OK;
135}
136
137status_t SurfaceTexture::setTransform(uint32_t transform) {
138 Mutex::Autolock lock(mMutex);
139 // XXX: How should we handle transforms?
140 return OK;
141}
142
143status_t SurfaceTexture::updateTexImage() {
144 Mutex::Autolock lock(mMutex);
145
146 // We always bind the texture even if we don't update its contents.
147 glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
148
149 // Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT,
150 // so this check will fail until a buffer gets queued.
151 if (mCurrentTexture != mLastQueued) {
152 // XXX: Figure out the right target.
153 mCurrentTexture = mLastQueued;
154 EGLImageKHR image = mSlots[mCurrentTexture].mEglImage;
155 if (image == EGL_NO_IMAGE_KHR) {
156 EGLDisplay dpy = eglGetCurrentDisplay();
157 sp<GraphicBuffer> graphicBuffer = mSlots[mCurrentTexture].mGraphicBuffer;
158 image = createImage(dpy, graphicBuffer);
159 mSlots[mCurrentTexture].mEglImage = image;
160 mSlots[mCurrentTexture].mEglDisplay = dpy;
161 }
162 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
163 GLint error = glGetError();
164 if (error != GL_NO_ERROR) {
165 LOGE("error binding external texture image %p (slot %d): %#04x",
166 image, mCurrentTexture, error);
167 return -EINVAL;
168 }
169 }
170 return OK;
171}
172
173void SurfaceTexture::freeAllBuffers() {
174 for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
175 mSlots[i].mGraphicBuffer = 0;
176 mSlots[i].mOwnedByClient = false;
177 if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
178 eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
179 mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
180 mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
181 }
182 }
183}
184
185EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
186 const sp<GraphicBuffer>& graphicBuffer) {
187 EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
188 EGLint attrs[] = {
189 EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
190 EGL_NONE,
191 };
192 EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
193 EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
194 EGLint error = eglGetError();
195 if (error != EGL_SUCCESS) {
196 LOGE("error creating EGLImage: %#x", error);
197 } else if (image == EGL_NO_IMAGE_KHR) {
198 LOGE("no error reported, but no image was returned by "
199 "eglCreateImageKHR");
200 }
201 return image;
202}
203
204}; // namespace android