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