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.
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.
15 #include "libEGL/Surface.h"
17 #include "common/debug.h"
18 #include "libGLESv2/Texture.h"
19 #include "libGLESv2/renderer/SwapChain.h"
20 #include "libGLESv2/main.h"
22 #include "libEGL/main.h"
23 #include "libEGL/Display.h"
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)
31 mRenderer = mDisplay->getRenderer();
35 mTextureFormat = EGL_NO_TEXTURE;
36 mTextureTarget = EGL_NO_TEXTURE;
38 mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio
39 mRenderBuffer = EGL_BACK_BUFFER;
40 mSwapBehavior = EGL_BUFFER_PRESERVED;
45 mFixedSize = fixedSize;
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)
53 mRenderer = mDisplay->getRenderer();
55 mWindowSubclassed = false;
57 mTextureFormat = textureFormat;
58 mTextureTarget = textureType;
60 mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio
61 mRenderBuffer = EGL_BACK_BUFFER;
62 mSwapBehavior = EGL_BUFFER_PRESERVED;
65 // This constructor is for offscreen surfaces, which are always fixed-size.
66 mFixedSize = EGL_TRUE;
75 bool Surface::initialize()
77 if (!resetSwapChain())
83 void Surface::release()
90 mTexture->releaseTexImage();
95 bool Surface::resetSwapChain()
105 if (!GetClientRect(getWindowHandle(), &windowRect))
109 ERR("Could not retrieve the window dimensions");
110 return error(EGL_BAD_SURFACE, false);
113 width = windowRect.right - windowRect.left;
114 height = windowRect.bottom - windowRect.top;
118 // non-window surface - size is determined at creation
123 mSwapChain = mRenderer->createSwapChain(mWindow, mShareHandle,
124 mConfig->mRenderTargetFormat,
125 mConfig->mDepthStencilFormat);
128 return error(EGL_BAD_ALLOC, false);
131 if (!resetSwapChain(width, height))
141 bool Surface::resizeSwapChain(int backbufferWidth, int backbufferHeight)
143 ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0);
146 EGLint status = mSwapChain->resize(std::max(1, backbufferWidth), std::max(1, backbufferHeight));
148 if (status == EGL_CONTEXT_LOST)
150 mDisplay->notifyDeviceLost();
153 else if (status != EGL_SUCCESS)
155 return error(status, false);
158 mWidth = backbufferWidth;
159 mHeight = backbufferHeight;
164 bool Surface::resetSwapChain(int backbufferWidth, int backbufferHeight)
166 ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0);
169 EGLint status = mSwapChain->reset(std::max(1, backbufferWidth), std::max(1, backbufferHeight), mSwapInterval);
171 if (status == EGL_CONTEXT_LOST)
173 mRenderer->notifyDeviceLost();
176 else if (status != EGL_SUCCESS)
178 return error(status, false);
181 mWidth = backbufferWidth;
182 mHeight = backbufferHeight;
183 mSwapIntervalDirty = false;
188 bool Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
195 if (x + width > mWidth)
200 if (y + height > mHeight)
202 height = mHeight - y;
205 if (width == 0 || height == 0)
210 EGLint status = mSwapChain->swapRect(x, y, width, height);
212 if (status == EGL_CONTEXT_LOST)
214 mRenderer->notifyDeviceLost();
217 else if (status != EGL_SUCCESS)
219 return error(status, false);
222 checkForOutOfDateSwapChain();
227 HWND Surface::getWindowHandle()
233 #define kSurfaceProperty _TEXT("Egl::SurfaceOwner")
234 #define kParentWndProc _TEXT("Egl::SurfaceParentWndProc")
236 static LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
238 if (message == WM_SIZE)
240 Surface* surf = reinterpret_cast<Surface*>(GetProp(hwnd, kSurfaceProperty));
243 surf->checkForOutOfDateSwapChain();
246 WNDPROC prevWndFunc = reinterpret_cast<WNDPROC >(GetProp(hwnd, kParentWndProc));
247 return CallWindowProc(prevWndFunc, hwnd, message, wparam, lparam);
250 void Surface::subclassWindow()
258 DWORD threadId = GetWindowThreadProcessId(mWindow, &processId);
259 if (processId != GetCurrentProcessId() || threadId != GetCurrentThreadId())
265 LONG_PTR oldWndProc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SurfaceWindowProc));
266 if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS)
268 mWindowSubclassed = false;
272 SetProp(mWindow, kSurfaceProperty, reinterpret_cast<HANDLE>(this));
273 SetProp(mWindow, kParentWndProc, reinterpret_cast<HANDLE>(oldWndProc));
274 mWindowSubclassed = true;
277 void Surface::unsubclassWindow()
279 if(!mWindowSubclassed)
285 LONG_PTR parentWndFunc = reinterpret_cast<LONG_PTR>(GetProp(mWindow, kParentWndProc));
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.
294 LONG_PTR prevWndFunc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, parentWndFunc);
295 ASSERT(prevWndFunc == reinterpret_cast<LONG_PTR>(SurfaceWindowProc));
298 RemoveProp(mWindow, kSurfaceProperty);
299 RemoveProp(mWindow, kParentWndProc);
300 mWindowSubclassed = false;
303 bool Surface::checkForOutOfDateSwapChain()
306 int clientWidth = getWidth();
307 int clientHeight = getHeight();
308 bool sizeDirty = false;
309 if (!mFixedSize && !IsIconic(getWindowHandle()))
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))
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();
325 bool wasDirty = (mSwapIntervalDirty || sizeDirty);
327 if (mSwapIntervalDirty)
329 resetSwapChain(clientWidth, clientHeight);
333 resizeSwapChain(clientWidth, clientHeight);
338 if (static_cast<egl::Surface*>(getCurrentDrawSurface()) == this)
340 glMakeCurrent(glGetCurrentContext(), static_cast<egl::Display*>(getCurrentDisplay()), this);
351 return swapRect(0, 0, mWidth, mHeight);
354 bool Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height)
356 if (!mPostSubBufferSupported)
358 // Spec is not clear about how this should be handled.
362 return swapRect(x, y, width, height);
365 EGLint Surface::getWidth() const
370 EGLint Surface::getHeight() const
375 EGLint Surface::isPostSubBufferSupported() const
377 return mPostSubBufferSupported;
380 rx::SwapChain *Surface::getSwapChain() const
385 void Surface::setSwapInterval(EGLint interval)
387 if (mSwapInterval == interval)
392 mSwapInterval = interval;
393 mSwapInterval = std::max(mSwapInterval, mRenderer->getMinSwapInterval());
394 mSwapInterval = std::min(mSwapInterval, mRenderer->getMaxSwapInterval());
396 mSwapIntervalDirty = true;
399 EGLenum Surface::getTextureFormat() const
401 return mTextureFormat;
404 EGLenum Surface::getTextureTarget() const
406 return mTextureTarget;
409 void Surface::setBoundTexture(gl::Texture2D *texture)
414 gl::Texture2D *Surface::getBoundTexture() const
419 EGLint Surface::isFixedSize() const
424 EGLenum Surface::getFormat() const
426 return mConfig->mRenderTargetFormat;