1 /* 2 * Copyright (C) 2011 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 #include "WindowSurface.h" 17 #include "FBConfig.h" 18 #include "FrameBuffer.h" 19 #include <GLES/glext.h> 20 #include "EGLDispatch.h" 21 #include "GLDispatch.h" 22 #include "GL2Dispatch.h" 23 #include <stdio.h> 24 #include <string.h> 25 #include "GLErrorLog.h" 26 27 WindowSurface::WindowSurface() : 28 m_fbObj(0), 29 m_depthRB(0), 30 m_stencilRB(0), 31 m_eglSurface(NULL), 32 m_attachedColorBuffer(NULL), 33 m_readContext(NULL), 34 m_drawContext(NULL), 35 m_width(0), 36 m_height(0), 37 m_pbufWidth(0), 38 m_pbufHeight(0) 39 { 40 } 41 42 WindowSurface::~WindowSurface() 43 { 44 s_egl.eglDestroySurface(FrameBuffer::getFB()->getDisplay(), m_eglSurface); 45 } 46 47 WindowSurface *WindowSurface::create(int p_config, int p_width, int p_height) 48 { 49 const FBConfig *fbconf = FBConfig::get(p_config); 50 if (!fbconf) { 51 return NULL; 52 } 53 54 // allocate space for the WindowSurface object 55 WindowSurface *win = new WindowSurface(); 56 if (!win) { 57 return NULL; 58 } 59 win->m_fbconf = fbconf; 60 61 FrameBuffer *fb = FrameBuffer::getFB(); 62 const FrameBufferCaps &caps = fb->getCaps(); 63 64 // 65 // Create a pbuffer to be used as the egl surface 66 // for that window. 67 // 68 if (!win->resizePbuffer(p_width, p_height)) { 69 delete win; 70 return NULL; 71 } 72 73 win->m_width = p_width; 74 win->m_height = p_height; 75 76 return win; 77 } 78 79 // 80 // flushColorBuffer - The function makes sure that the 81 // previous attached color buffer is updated, if copy or blit should be done 82 // in order to update it - it is being done here. 83 // 84 void WindowSurface::flushColorBuffer() 85 { 86 if (m_attachedColorBuffer.Ptr() != NULL) { 87 blitToColorBuffer(); 88 } 89 } 90 91 // 92 // setColorBuffer - this function is called when a new color buffer needs to 93 // be attached to the surface. The function doesn't make sure that the 94 // previous attached color buffer is updated, this is done by flushColorBuffer 95 // 96 void WindowSurface::setColorBuffer(ColorBufferPtr p_colorBuffer) 97 { 98 m_attachedColorBuffer = p_colorBuffer; 99 100 // 101 // resize the window if the attached color buffer is of different 102 // size 103 // 104 unsigned int cbWidth = m_attachedColorBuffer->getWidth(); 105 unsigned int cbHeight = m_attachedColorBuffer->getHeight(); 106 107 if (cbWidth != m_width || cbHeight != m_height) { 108 109 if (m_pbufWidth && m_pbufHeight) { 110 // if we use pbuffer, need to resize it 111 resizePbuffer(cbWidth, cbHeight); 112 } 113 114 m_width = cbWidth; 115 m_height = cbHeight; 116 } 117 } 118 119 // 120 // This function is called after the context and eglSurface is already 121 // bound in the current thread (eglMakeCurrent has been called). 122 // This function should take actions required on the other surface objects 123 // when being bind/unbound 124 // 125 void WindowSurface::bind(RenderContextPtr p_ctx, SurfaceBindType p_bindType) 126 { 127 if (p_bindType == SURFACE_BIND_READ) { 128 m_readContext = p_ctx; 129 } 130 else if (p_bindType == SURFACE_BIND_DRAW) { 131 m_drawContext = p_ctx; 132 } 133 else if (p_bindType == SURFACE_BIND_READDRAW) { 134 m_readContext = p_ctx; 135 m_drawContext = p_ctx; 136 } 137 else { 138 return; // bad param 139 } 140 141 } 142 143 void WindowSurface::blitToColorBuffer() 144 { 145 if (!m_width && !m_height) return; 146 147 if (m_attachedColorBuffer->getWidth() != m_width || 148 m_attachedColorBuffer->getHeight() != m_height) { 149 // XXX: should never happen - how this needs to be handled? 150 return; 151 } 152 153 // 154 // Make the surface current 155 // 156 EGLContext prevContext = s_egl.eglGetCurrentContext(); 157 EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ); 158 EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW); 159 FrameBuffer *fb = FrameBuffer::getFB(); 160 if (!s_egl.eglMakeCurrent(fb->getDisplay(), m_eglSurface, 161 m_eglSurface, m_drawContext->getEGLContext())) { 162 return; 163 } 164 165 m_attachedColorBuffer->blitFromCurrentReadBuffer(); 166 167 // restore current context/surface 168 s_egl.eglMakeCurrent(fb->getDisplay(), prevDrawSurf, 169 prevReadSurf, prevContext); 170 171 } 172 173 bool WindowSurface::resizePbuffer(unsigned int p_width, unsigned int p_height) 174 { 175 if (m_eglSurface && 176 m_pbufWidth == p_width && 177 m_pbufHeight == p_height) { 178 // no need to resize 179 return true; 180 } 181 182 FrameBuffer *fb = FrameBuffer::getFB(); 183 184 EGLContext prevContext = s_egl.eglGetCurrentContext(); 185 EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ); 186 EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW); 187 EGLSurface prevPbuf = m_eglSurface; 188 bool needRebindContext = m_eglSurface && 189 (prevReadSurf == m_eglSurface || 190 prevDrawSurf == m_eglSurface); 191 192 if (needRebindContext) { 193 s_egl.eglMakeCurrent(fb->getDisplay(), EGL_NO_SURFACE, 194 EGL_NO_SURFACE, EGL_NO_CONTEXT); 195 } 196 197 // 198 // Destroy previous surface 199 // 200 if (m_eglSurface) { 201 s_egl.eglDestroySurface(fb->getDisplay(), m_eglSurface); 202 m_eglSurface = NULL; 203 } 204 205 const FrameBufferCaps &caps = fb->getCaps(); 206 207 // 208 // Create pbuffer surface. 209 // 210 EGLint pbufAttribs[5]; 211 pbufAttribs[0] = EGL_WIDTH; 212 pbufAttribs[1] = p_width; 213 pbufAttribs[2] = EGL_HEIGHT; 214 pbufAttribs[3] = p_height; 215 pbufAttribs[4] = EGL_NONE; 216 217 m_eglSurface = s_egl.eglCreatePbufferSurface(fb->getDisplay(), 218 m_fbconf->getEGLConfig(), 219 pbufAttribs); 220 if (m_eglSurface == EGL_NO_SURFACE) { 221 fprintf(stderr, "Renderer error: failed to create/resize pbuffer!!\n"); 222 return false; 223 } 224 225 m_pbufWidth = p_width; 226 m_pbufHeight = p_height; 227 228 if (needRebindContext) { 229 s_egl.eglMakeCurrent(fb->getDisplay(), 230 (prevDrawSurf==prevPbuf) ? m_eglSurface : prevDrawSurf, 231 (prevReadSurf==prevPbuf) ? m_eglSurface : prevReadSurf, 232 prevContext); 233 } 234 235 return true; 236 } 237