• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // Surface.cpp: Implements the egl::Surface class, representing a drawing surface
8 // such as the client area of a window, including any back buffers.
9 // Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3.
10 
11 #include <tchar.h>
12 
13 #include <algorithm>
14 
15 #include "libEGL/Surface.h"
16 
17 #include "common/debug.h"
18 #include "libGLESv2/Texture.h"
19 #include "libGLESv2/renderer/SwapChain.h"
20 #include "libGLESv2/main.h"
21 
22 #include "libEGL/main.h"
23 #include "libEGL/Display.h"
24 
25 namespace egl
26 {
27 
Surface(Display * display,const Config * config,HWND window,EGLint postSubBufferSupported)28 Surface::Surface(Display *display, const Config *config, HWND window, EGLint postSubBufferSupported)
29     : mDisplay(display), mConfig(config), mWindow(window), mPostSubBufferSupported(postSubBufferSupported)
30 {
31     mRenderer = mDisplay->getRenderer();
32     mSwapChain = NULL;
33     mShareHandle = NULL;
34     mTexture = NULL;
35     mTextureFormat = EGL_NO_TEXTURE;
36     mTextureTarget = EGL_NO_TEXTURE;
37 
38     mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING);   // FIXME: Determine actual pixel aspect ratio
39     mRenderBuffer = EGL_BACK_BUFFER;
40     mSwapBehavior = EGL_BUFFER_PRESERVED;
41     mSwapInterval = -1;
42     mWidth = -1;
43     mHeight = -1;
44     setSwapInterval(1);
45 
46     subclassWindow();
47 }
48 
Surface(Display * display,const Config * config,HANDLE shareHandle,EGLint width,EGLint height,EGLenum textureFormat,EGLenum textureType)49 Surface::Surface(Display *display, const Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureType)
50     : mDisplay(display), mWindow(NULL), mConfig(config), mShareHandle(shareHandle), mWidth(width), mHeight(height), mPostSubBufferSupported(EGL_FALSE)
51 {
52     mRenderer = mDisplay->getRenderer();
53     mSwapChain = NULL;
54     mWindowSubclassed = false;
55     mTexture = NULL;
56     mTextureFormat = textureFormat;
57     mTextureTarget = textureType;
58 
59     mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING);   // FIXME: Determine actual pixel aspect ratio
60     mRenderBuffer = EGL_BACK_BUFFER;
61     mSwapBehavior = EGL_BUFFER_PRESERVED;
62     mSwapInterval = -1;
63     setSwapInterval(1);
64 }
65 
~Surface()66 Surface::~Surface()
67 {
68     unsubclassWindow();
69     release();
70 }
71 
initialize()72 bool Surface::initialize()
73 {
74     if (!resetSwapChain())
75       return false;
76 
77     return true;
78 }
79 
release()80 void Surface::release()
81 {
82     delete mSwapChain;
83     mSwapChain = NULL;
84 
85     if (mTexture)
86     {
87         mTexture->releaseTexImage();
88         mTexture = NULL;
89     }
90 }
91 
resetSwapChain()92 bool Surface::resetSwapChain()
93 {
94     ASSERT(!mSwapChain);
95 
96     int width;
97     int height;
98 
99     if (mWindow)
100     {
101         RECT windowRect;
102         if (!GetClientRect(getWindowHandle(), &windowRect))
103         {
104             ASSERT(false);
105 
106             ERR("Could not retrieve the window dimensions");
107             return error(EGL_BAD_SURFACE, false);
108         }
109 
110         width = windowRect.right - windowRect.left;
111         height = windowRect.bottom - windowRect.top;
112     }
113     else
114     {
115         // non-window surface - size is determined at creation
116         width = mWidth;
117         height = mHeight;
118     }
119 
120     mSwapChain = mRenderer->createSwapChain(mWindow, mShareHandle,
121                                             mConfig->mRenderTargetFormat,
122                                             mConfig->mDepthStencilFormat);
123     if (!mSwapChain)
124     {
125         return error(EGL_BAD_ALLOC, false);
126     }
127 
128     if (!resetSwapChain(width, height))
129     {
130         delete mSwapChain;
131         mSwapChain = NULL;
132         return false;
133     }
134 
135     return true;
136 }
137 
resizeSwapChain(int backbufferWidth,int backbufferHeight)138 bool Surface::resizeSwapChain(int backbufferWidth, int backbufferHeight)
139 {
140     ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0);
141     ASSERT(mSwapChain);
142 
143     EGLint status = mSwapChain->resize(backbufferWidth, backbufferHeight);
144 
145     if (status == EGL_CONTEXT_LOST)
146     {
147         mDisplay->notifyDeviceLost();
148         return false;
149     }
150     else if (status != EGL_SUCCESS)
151     {
152         return error(status, false);
153     }
154 
155     mWidth = backbufferWidth;
156     mHeight = backbufferHeight;
157 
158     return true;
159 }
160 
resetSwapChain(int backbufferWidth,int backbufferHeight)161 bool Surface::resetSwapChain(int backbufferWidth, int backbufferHeight)
162 {
163     ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0);
164     ASSERT(mSwapChain);
165 
166     EGLint status = mSwapChain->reset(backbufferWidth, backbufferHeight, mSwapInterval);
167 
168     if (status == EGL_CONTEXT_LOST)
169     {
170         mRenderer->notifyDeviceLost();
171         return false;
172     }
173     else if (status != EGL_SUCCESS)
174     {
175         return error(status, false);
176     }
177 
178     mWidth = backbufferWidth;
179     mHeight = backbufferHeight;
180     mSwapIntervalDirty = false;
181 
182     return true;
183 }
184 
swapRect(EGLint x,EGLint y,EGLint width,EGLint height)185 bool Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
186 {
187     if (!mSwapChain)
188     {
189         return true;
190     }
191 
192     if (x + width > mWidth)
193     {
194         width = mWidth - x;
195     }
196 
197     if (y + height > mHeight)
198     {
199         height = mHeight - y;
200     }
201 
202     if (width == 0 || height == 0)
203     {
204         return true;
205     }
206 
207     EGLint status = mSwapChain->swapRect(x, y, width, height);
208 
209     if (status == EGL_CONTEXT_LOST)
210     {
211         mRenderer->notifyDeviceLost();
212         return false;
213     }
214     else if (status != EGL_SUCCESS)
215     {
216         return error(status, false);
217     }
218 
219     checkForOutOfDateSwapChain();
220 
221     return true;
222 }
223 
getWindowHandle()224 HWND Surface::getWindowHandle()
225 {
226     return mWindow;
227 }
228 
229 
230 #define kSurfaceProperty _TEXT("Egl::SurfaceOwner")
231 #define kParentWndProc _TEXT("Egl::SurfaceParentWndProc")
232 
SurfaceWindowProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)233 static LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
234 {
235   if (message == WM_SIZE)
236   {
237       Surface* surf = reinterpret_cast<Surface*>(GetProp(hwnd, kSurfaceProperty));
238       if(surf)
239       {
240           surf->checkForOutOfDateSwapChain();
241       }
242   }
243   WNDPROC prevWndFunc = reinterpret_cast<WNDPROC >(GetProp(hwnd, kParentWndProc));
244   return CallWindowProc(prevWndFunc, hwnd, message, wparam, lparam);
245 }
246 
subclassWindow()247 void Surface::subclassWindow()
248 {
249     if (!mWindow)
250     {
251         return;
252     }
253 
254     DWORD processId;
255     DWORD threadId = GetWindowThreadProcessId(mWindow, &processId);
256     if (processId != GetCurrentProcessId() || threadId != GetCurrentThreadId())
257     {
258         return;
259     }
260 
261     SetLastError(0);
262     LONG_PTR oldWndProc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SurfaceWindowProc));
263     if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS)
264     {
265         mWindowSubclassed = false;
266         return;
267     }
268 
269     SetProp(mWindow, kSurfaceProperty, reinterpret_cast<HANDLE>(this));
270     SetProp(mWindow, kParentWndProc, reinterpret_cast<HANDLE>(oldWndProc));
271     mWindowSubclassed = true;
272 }
273 
unsubclassWindow()274 void Surface::unsubclassWindow()
275 {
276     if(!mWindowSubclassed)
277     {
278         return;
279     }
280 
281     // un-subclass
282     LONG_PTR parentWndFunc = reinterpret_cast<LONG_PTR>(GetProp(mWindow, kParentWndProc));
283 
284     // Check the windowproc is still SurfaceWindowProc.
285     // If this assert fails, then it is likely the application has subclassed the
286     // hwnd as well and did not unsubclass before destroying its EGL context. The
287     // application should be modified to either subclass before initializing the
288     // EGL context, or to unsubclass before destroying the EGL context.
289     if(parentWndFunc)
290     {
291         LONG_PTR prevWndFunc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, parentWndFunc);
292         ASSERT(prevWndFunc == reinterpret_cast<LONG_PTR>(SurfaceWindowProc));
293     }
294 
295     RemoveProp(mWindow, kSurfaceProperty);
296     RemoveProp(mWindow, kParentWndProc);
297     mWindowSubclassed = false;
298 }
299 
checkForOutOfDateSwapChain()300 bool Surface::checkForOutOfDateSwapChain()
301 {
302     RECT client;
303     if (!GetClientRect(getWindowHandle(), &client))
304     {
305         ASSERT(false);
306         return false;
307     }
308 
309     // Grow the buffer now, if the window has grown. We need to grow now to avoid losing information.
310     int clientWidth = client.right - client.left;
311     int clientHeight = client.bottom - client.top;
312     bool sizeDirty = clientWidth != getWidth() || clientHeight != getHeight();
313 
314     if (IsIconic(getWindowHandle()))
315     {
316         // The window is automatically resized to 150x22 when it's minimized, but the swapchain shouldn't be resized
317         // because that's not a useful size to render to.
318         sizeDirty = false;
319     }
320 
321     if (mSwapIntervalDirty)
322     {
323         resetSwapChain(clientWidth, clientHeight);
324     }
325     else if (sizeDirty)
326     {
327         resizeSwapChain(clientWidth, clientHeight);
328     }
329 
330     if (mSwapIntervalDirty || sizeDirty)
331     {
332         if (static_cast<egl::Surface*>(getCurrentDrawSurface()) == this)
333         {
334             glMakeCurrent(glGetCurrentContext(), static_cast<egl::Display*>(getCurrentDisplay()), this);
335         }
336 
337         return true;
338     }
339 
340     return false;
341 }
342 
swap()343 bool Surface::swap()
344 {
345     return swapRect(0, 0, mWidth, mHeight);
346 }
347 
postSubBuffer(EGLint x,EGLint y,EGLint width,EGLint height)348 bool Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height)
349 {
350     if (!mPostSubBufferSupported)
351     {
352         // Spec is not clear about how this should be handled.
353         return true;
354     }
355 
356     return swapRect(x, y, width, height);
357 }
358 
getWidth() const359 EGLint Surface::getWidth() const
360 {
361     return mWidth;
362 }
363 
getHeight() const364 EGLint Surface::getHeight() const
365 {
366     return mHeight;
367 }
368 
isPostSubBufferSupported() const369 EGLint Surface::isPostSubBufferSupported() const
370 {
371     return mPostSubBufferSupported;
372 }
373 
getSwapChain() const374 rx::SwapChain *Surface::getSwapChain() const
375 {
376     return mSwapChain;
377 }
378 
setSwapInterval(EGLint interval)379 void Surface::setSwapInterval(EGLint interval)
380 {
381     if (mSwapInterval == interval)
382     {
383         return;
384     }
385 
386     mSwapInterval = interval;
387     mSwapInterval = std::max(mSwapInterval, mRenderer->getMinSwapInterval());
388     mSwapInterval = std::min(mSwapInterval, mRenderer->getMaxSwapInterval());
389 
390     mSwapIntervalDirty = true;
391 }
392 
getTextureFormat() const393 EGLenum Surface::getTextureFormat() const
394 {
395     return mTextureFormat;
396 }
397 
getTextureTarget() const398 EGLenum Surface::getTextureTarget() const
399 {
400     return mTextureTarget;
401 }
402 
setBoundTexture(gl::Texture2D * texture)403 void Surface::setBoundTexture(gl::Texture2D *texture)
404 {
405     mTexture = texture;
406 }
407 
getBoundTexture() const408 gl::Texture2D *Surface::getBoundTexture() const
409 {
410     return mTexture;
411 }
412 
getFormat() const413 EGLenum Surface::getFormat() const
414 {
415     return mConfig->mRenderTargetFormat;
416 }
417 }
418