Home | History | Annotate | Download | only in libOpenglRender
      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