• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
WindowSurface()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 
~WindowSurface()42 WindowSurface::~WindowSurface()
43 {
44     s_egl.eglDestroySurface(FrameBuffer::getFB()->getDisplay(), m_eglSurface);
45 }
46 
create(int p_config,int p_width,int p_height)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 //
flushColorBuffer()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 //
setColorBuffer(ColorBufferPtr p_colorBuffer)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 //
bind(RenderContextPtr p_ctx,SurfaceBindType p_bindType)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 
blitToColorBuffer()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 
resizePbuffer(unsigned int p_width,unsigned int p_height)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