1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/angle/src/libEGL/Surface.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,410 @@ 1.4 +// 1.5 +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. 1.6 +// Use of this source code is governed by a BSD-style license that can be 1.7 +// found in the LICENSE file. 1.8 +// 1.9 + 1.10 +// Surface.cpp: Implements the egl::Surface class, representing a drawing surface 1.11 +// such as the client area of a window, including any back buffers. 1.12 +// Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3. 1.13 + 1.14 +#include <tchar.h> 1.15 + 1.16 +#include "libEGL/Surface.h" 1.17 + 1.18 +#include "common/debug.h" 1.19 +#include "libGLESv2/Texture.h" 1.20 +#include "libGLESv2/renderer/SwapChain.h" 1.21 +#include "libGLESv2/main.h" 1.22 + 1.23 +#include "libEGL/main.h" 1.24 +#include "libEGL/Display.h" 1.25 + 1.26 +#include <algorithm> 1.27 + 1.28 +namespace egl 1.29 +{ 1.30 + 1.31 +Surface::Surface(Display *display, const Config *config, HWND window, EGLint postSubBufferSupported) 1.32 + : mDisplay(display), mConfig(config), mWindow(window), mPostSubBufferSupported(postSubBufferSupported) 1.33 +{ 1.34 + mRenderer = mDisplay->getRenderer(); 1.35 + mSwapChain = NULL; 1.36 + mShareHandle = NULL; 1.37 + mTexture = NULL; 1.38 + mTextureFormat = EGL_NO_TEXTURE; 1.39 + mTextureTarget = EGL_NO_TEXTURE; 1.40 + 1.41 + mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio 1.42 + mRenderBuffer = EGL_BACK_BUFFER; 1.43 + mSwapBehavior = EGL_BUFFER_PRESERVED; 1.44 + mSwapInterval = -1; 1.45 + mWidth = -1; 1.46 + mHeight = -1; 1.47 + setSwapInterval(1); 1.48 + 1.49 + subclassWindow(); 1.50 +} 1.51 + 1.52 +Surface::Surface(Display *display, const Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureType) 1.53 + : mDisplay(display), mWindow(NULL), mConfig(config), mShareHandle(shareHandle), mWidth(width), mHeight(height), mPostSubBufferSupported(EGL_FALSE) 1.54 +{ 1.55 + mRenderer = mDisplay->getRenderer(); 1.56 + mSwapChain = NULL; 1.57 + mWindowSubclassed = false; 1.58 + mTexture = NULL; 1.59 + mTextureFormat = textureFormat; 1.60 + mTextureTarget = textureType; 1.61 + 1.62 + mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio 1.63 + mRenderBuffer = EGL_BACK_BUFFER; 1.64 + mSwapBehavior = EGL_BUFFER_PRESERVED; 1.65 + mSwapInterval = -1; 1.66 + setSwapInterval(1); 1.67 +} 1.68 + 1.69 +Surface::~Surface() 1.70 +{ 1.71 + unsubclassWindow(); 1.72 + release(); 1.73 +} 1.74 + 1.75 +bool Surface::initialize() 1.76 +{ 1.77 + if (!resetSwapChain()) 1.78 + return false; 1.79 + 1.80 + return true; 1.81 +} 1.82 + 1.83 +void Surface::release() 1.84 +{ 1.85 + delete mSwapChain; 1.86 + mSwapChain = NULL; 1.87 + 1.88 + if (mTexture) 1.89 + { 1.90 + mTexture->releaseTexImage(); 1.91 + mTexture = NULL; 1.92 + } 1.93 +} 1.94 + 1.95 +bool Surface::resetSwapChain() 1.96 +{ 1.97 + ASSERT(!mSwapChain); 1.98 + 1.99 + int width; 1.100 + int height; 1.101 + 1.102 + if (mWindow) 1.103 + { 1.104 + RECT windowRect; 1.105 + if (!GetClientRect(getWindowHandle(), &windowRect)) 1.106 + { 1.107 + ASSERT(false); 1.108 + 1.109 + ERR("Could not retrieve the window dimensions"); 1.110 + return error(EGL_BAD_SURFACE, false); 1.111 + } 1.112 + 1.113 + width = windowRect.right - windowRect.left; 1.114 + height = windowRect.bottom - windowRect.top; 1.115 + } 1.116 + else 1.117 + { 1.118 + // non-window surface - size is determined at creation 1.119 + width = mWidth; 1.120 + height = mHeight; 1.121 + } 1.122 + 1.123 + mSwapChain = mRenderer->createSwapChain(mWindow, mShareHandle, 1.124 + mConfig->mRenderTargetFormat, 1.125 + mConfig->mDepthStencilFormat); 1.126 + if (!mSwapChain) 1.127 + { 1.128 + return error(EGL_BAD_ALLOC, false); 1.129 + } 1.130 + 1.131 + if (!resetSwapChain(width, height)) 1.132 + { 1.133 + delete mSwapChain; 1.134 + mSwapChain = NULL; 1.135 + return false; 1.136 + } 1.137 + 1.138 + return true; 1.139 +} 1.140 + 1.141 +bool Surface::resizeSwapChain(int backbufferWidth, int backbufferHeight) 1.142 +{ 1.143 + ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); 1.144 + ASSERT(mSwapChain); 1.145 + 1.146 + EGLint status = mSwapChain->resize(backbufferWidth, backbufferHeight); 1.147 + 1.148 + if (status == EGL_CONTEXT_LOST) 1.149 + { 1.150 + mDisplay->notifyDeviceLost(); 1.151 + return false; 1.152 + } 1.153 + else if (status != EGL_SUCCESS) 1.154 + { 1.155 + return error(status, false); 1.156 + } 1.157 + 1.158 + mWidth = backbufferWidth; 1.159 + mHeight = backbufferHeight; 1.160 + 1.161 + return true; 1.162 +} 1.163 + 1.164 +bool Surface::resetSwapChain(int backbufferWidth, int backbufferHeight) 1.165 +{ 1.166 + ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); 1.167 + ASSERT(mSwapChain); 1.168 + 1.169 + EGLint status = mSwapChain->reset(backbufferWidth, backbufferHeight, mSwapInterval); 1.170 + 1.171 + if (status == EGL_CONTEXT_LOST) 1.172 + { 1.173 + mRenderer->notifyDeviceLost(); 1.174 + return false; 1.175 + } 1.176 + else if (status != EGL_SUCCESS) 1.177 + { 1.178 + return error(status, false); 1.179 + } 1.180 + 1.181 + mWidth = backbufferWidth; 1.182 + mHeight = backbufferHeight; 1.183 + mSwapIntervalDirty = false; 1.184 + 1.185 + return true; 1.186 +} 1.187 + 1.188 +bool Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) 1.189 +{ 1.190 + if (!mSwapChain) 1.191 + { 1.192 + return true; 1.193 + } 1.194 + 1.195 + if (x + width > mWidth) 1.196 + { 1.197 + width = mWidth - x; 1.198 + } 1.199 + 1.200 + if (y + height > mHeight) 1.201 + { 1.202 + height = mHeight - y; 1.203 + } 1.204 + 1.205 + if (width == 0 || height == 0) 1.206 + { 1.207 + return true; 1.208 + } 1.209 + 1.210 + EGLint status = mSwapChain->swapRect(x, y, width, height); 1.211 + 1.212 + if (status == EGL_CONTEXT_LOST) 1.213 + { 1.214 + mRenderer->notifyDeviceLost(); 1.215 + return false; 1.216 + } 1.217 + else if (status != EGL_SUCCESS) 1.218 + { 1.219 + return error(status, false); 1.220 + } 1.221 + 1.222 + checkForOutOfDateSwapChain(); 1.223 + 1.224 + return true; 1.225 +} 1.226 + 1.227 +HWND Surface::getWindowHandle() 1.228 +{ 1.229 + return mWindow; 1.230 +} 1.231 + 1.232 + 1.233 +#define kSurfaceProperty _TEXT("Egl::SurfaceOwner") 1.234 +#define kParentWndProc _TEXT("Egl::SurfaceParentWndProc") 1.235 + 1.236 +static LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) 1.237 +{ 1.238 + if (message == WM_SIZE) 1.239 + { 1.240 + Surface* surf = reinterpret_cast<Surface*>(GetProp(hwnd, kSurfaceProperty)); 1.241 + if(surf) 1.242 + { 1.243 + surf->checkForOutOfDateSwapChain(); 1.244 + } 1.245 + } 1.246 + WNDPROC prevWndFunc = reinterpret_cast<WNDPROC >(GetProp(hwnd, kParentWndProc)); 1.247 + return CallWindowProc(prevWndFunc, hwnd, message, wparam, lparam); 1.248 +} 1.249 + 1.250 +void Surface::subclassWindow() 1.251 +{ 1.252 + if (!mWindow) 1.253 + { 1.254 + return; 1.255 + } 1.256 + 1.257 + DWORD processId; 1.258 + DWORD threadId = GetWindowThreadProcessId(mWindow, &processId); 1.259 + if (processId != GetCurrentProcessId() || threadId != GetCurrentThreadId()) 1.260 + { 1.261 + return; 1.262 + } 1.263 + 1.264 + SetLastError(0); 1.265 + LONG_PTR oldWndProc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SurfaceWindowProc)); 1.266 + if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS) 1.267 + { 1.268 + mWindowSubclassed = false; 1.269 + return; 1.270 + } 1.271 + 1.272 + SetProp(mWindow, kSurfaceProperty, reinterpret_cast<HANDLE>(this)); 1.273 + SetProp(mWindow, kParentWndProc, reinterpret_cast<HANDLE>(oldWndProc)); 1.274 + mWindowSubclassed = true; 1.275 +} 1.276 + 1.277 +void Surface::unsubclassWindow() 1.278 +{ 1.279 + if(!mWindowSubclassed) 1.280 + { 1.281 + return; 1.282 + } 1.283 + 1.284 + // un-subclass 1.285 + LONG_PTR parentWndFunc = reinterpret_cast<LONG_PTR>(GetProp(mWindow, kParentWndProc)); 1.286 + 1.287 + // Check the windowproc is still SurfaceWindowProc. 1.288 + // If this assert fails, then it is likely the application has subclassed the 1.289 + // hwnd as well and did not unsubclass before destroying its EGL context. The 1.290 + // application should be modified to either subclass before initializing the 1.291 + // EGL context, or to unsubclass before destroying the EGL context. 1.292 + if(parentWndFunc) 1.293 + { 1.294 + LONG_PTR prevWndFunc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, parentWndFunc); 1.295 + ASSERT(prevWndFunc == reinterpret_cast<LONG_PTR>(SurfaceWindowProc)); 1.296 + } 1.297 + 1.298 + RemoveProp(mWindow, kSurfaceProperty); 1.299 + RemoveProp(mWindow, kParentWndProc); 1.300 + mWindowSubclassed = false; 1.301 +} 1.302 + 1.303 +bool Surface::checkForOutOfDateSwapChain() 1.304 +{ 1.305 + RECT client; 1.306 + if (!GetClientRect(getWindowHandle(), &client)) 1.307 + { 1.308 + ASSERT(false); 1.309 + return false; 1.310 + } 1.311 + 1.312 + // Grow the buffer now, if the window has grown. We need to grow now to avoid losing information. 1.313 + int clientWidth = client.right - client.left; 1.314 + int clientHeight = client.bottom - client.top; 1.315 + bool sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); 1.316 + 1.317 + if (mSwapIntervalDirty) 1.318 + { 1.319 + resetSwapChain(clientWidth, clientHeight); 1.320 + } 1.321 + else if (sizeDirty) 1.322 + { 1.323 + resizeSwapChain(clientWidth, clientHeight); 1.324 + } 1.325 + 1.326 + if (mSwapIntervalDirty || sizeDirty) 1.327 + { 1.328 + if (static_cast<egl::Surface*>(getCurrentDrawSurface()) == this) 1.329 + { 1.330 + glMakeCurrent(glGetCurrentContext(), static_cast<egl::Display*>(getCurrentDisplay()), this); 1.331 + } 1.332 + 1.333 + return true; 1.334 + } 1.335 + 1.336 + return false; 1.337 +} 1.338 + 1.339 +bool Surface::swap() 1.340 +{ 1.341 + return swapRect(0, 0, mWidth, mHeight); 1.342 +} 1.343 + 1.344 +bool Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) 1.345 +{ 1.346 + if (!mPostSubBufferSupported) 1.347 + { 1.348 + // Spec is not clear about how this should be handled. 1.349 + return true; 1.350 + } 1.351 + 1.352 + return swapRect(x, y, width, height); 1.353 +} 1.354 + 1.355 +EGLint Surface::getWidth() const 1.356 +{ 1.357 + return mWidth; 1.358 +} 1.359 + 1.360 +EGLint Surface::getHeight() const 1.361 +{ 1.362 + return mHeight; 1.363 +} 1.364 + 1.365 +EGLint Surface::isPostSubBufferSupported() const 1.366 +{ 1.367 + return mPostSubBufferSupported; 1.368 +} 1.369 + 1.370 +rx::SwapChain *Surface::getSwapChain() const 1.371 +{ 1.372 + return mSwapChain; 1.373 +} 1.374 + 1.375 +void Surface::setSwapInterval(EGLint interval) 1.376 +{ 1.377 + if (mSwapInterval == interval) 1.378 + { 1.379 + return; 1.380 + } 1.381 + 1.382 + mSwapInterval = interval; 1.383 + mSwapInterval = std::max(mSwapInterval, mRenderer->getMinSwapInterval()); 1.384 + mSwapInterval = std::min(mSwapInterval, mRenderer->getMaxSwapInterval()); 1.385 + 1.386 + mSwapIntervalDirty = true; 1.387 +} 1.388 + 1.389 +EGLenum Surface::getTextureFormat() const 1.390 +{ 1.391 + return mTextureFormat; 1.392 +} 1.393 + 1.394 +EGLenum Surface::getTextureTarget() const 1.395 +{ 1.396 + return mTextureTarget; 1.397 +} 1.398 + 1.399 +void Surface::setBoundTexture(gl::Texture2D *texture) 1.400 +{ 1.401 + mTexture = texture; 1.402 +} 1.403 + 1.404 +gl::Texture2D *Surface::getBoundTexture() const 1.405 +{ 1.406 + return mTexture; 1.407 +} 1.408 + 1.409 +EGLenum Surface::getFormat() const 1.410 +{ 1.411 + return mConfig->mRenderTargetFormat; 1.412 +} 1.413 +}