gfx/angle/src/libEGL/Surface.cpp

changeset 0
6474c204b198
     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 +}

mercurial