Home | History | Annotate | Download | only in libGL
      1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //    http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 // Surface.cpp: Implements the Surface class, representing a drawing surface
     16 // such as the client area of a window, including any back buffers.
     17 
     18 #include "Surface.h"
     19 
     20 #include "main.h"
     21 #include "Display.h"
     22 #include "Image.hpp"
     23 #include "Context.h"
     24 #include "common/debug.h"
     25 #include "Main/FrameBuffer.hpp"
     26 
     27 #if defined(_WIN32)
     28 #include <tchar.h>
     29 #endif
     30 
     31 #include <algorithm>
     32 
     33 namespace gl
     34 {
     35 
     36 Surface::Surface(Display *display, NativeWindowType window)
     37 	: mDisplay(display), mWindow(window)
     38 {
     39 	frameBuffer = 0;
     40 	backBuffer = 0;
     41 
     42 	mDepthStencil = nullptr;
     43 	mTextureFormat = GL_NONE;
     44 	mTextureTarget = GL_NONE;
     45 
     46 	mSwapInterval = -1;
     47 	setSwapInterval(1);
     48 }
     49 
     50 Surface::Surface(Display *display, GLint width, GLint height, GLenum textureFormat, GLenum textureType)
     51 	: mDisplay(display), mWindow(nullptr), mWidth(width), mHeight(height)
     52 {
     53 	frameBuffer = 0;
     54 	backBuffer = 0;
     55 
     56 	mDepthStencil = nullptr;
     57 	mWindowSubclassed = false;
     58 	mTextureFormat = textureFormat;
     59 	mTextureTarget = textureType;
     60 
     61 	mSwapInterval = -1;
     62 	setSwapInterval(1);
     63 }
     64 
     65 Surface::~Surface()
     66 {
     67 	release();
     68 }
     69 
     70 bool Surface::initialize()
     71 {
     72 	ASSERT(!frameBuffer && !backBuffer && !mDepthStencil);
     73 
     74 	return reset();
     75 }
     76 
     77 void Surface::release()
     78 {
     79 	if(mDepthStencil)
     80 	{
     81 		mDepthStencil->release();
     82 		mDepthStencil = nullptr;
     83 	}
     84 
     85 	if(backBuffer)
     86 	{
     87 		backBuffer->release();
     88 		backBuffer = 0;
     89 	}
     90 
     91 	delete frameBuffer;
     92 	frameBuffer = 0;
     93 }
     94 
     95 bool Surface::reset()
     96 {
     97 	if(!mWindow)
     98 	{
     99 		return reset(mWidth, mHeight);
    100 	}
    101 
    102 	// FIXME: Wrap into an abstract Window class
    103 	#if defined(_WIN32)
    104 		RECT windowRect;
    105 		GetClientRect(mWindow, &windowRect);
    106 
    107 		return reset(windowRect.right - windowRect.left, windowRect.bottom - windowRect.top);
    108 	#else
    109 		XWindowAttributes windowAttributes;
    110 		XGetWindowAttributes(mDisplay->getNativeDisplay(), mWindow, &windowAttributes);
    111 
    112 		return reset(windowAttributes.width, windowAttributes.height);
    113 	#endif
    114 }
    115 
    116 bool Surface::reset(int backBufferWidth, int backBufferHeight)
    117 {
    118 	release();
    119 
    120 	if(mWindow)
    121 	{
    122 		frameBuffer = ::createFrameBuffer(mDisplay->getNativeDisplay(), mWindow, backBufferWidth, backBufferHeight);
    123 
    124 		if(!frameBuffer)
    125 		{
    126 			ERR("Could not create frame buffer");
    127 			release();
    128 			return error(GL_OUT_OF_MEMORY, false);
    129 		}
    130 	}
    131 
    132 	backBuffer = new Image(0, backBufferWidth, backBufferHeight, GL_RGB, GL_UNSIGNED_BYTE);
    133 
    134 	if(!backBuffer)
    135 	{
    136 		ERR("Could not create back buffer");
    137 		release();
    138 		return error(GL_OUT_OF_MEMORY, false);
    139 	}
    140 
    141 	if(true)   // Always provide a depth/stencil buffer
    142 	{
    143 		mDepthStencil = new Image(0, backBufferWidth, backBufferHeight, sw::FORMAT_D24S8, 1, false, true);
    144 
    145 		if(!mDepthStencil)
    146 		{
    147 			ERR("Could not create depth/stencil buffer for surface");
    148 			release();
    149 			return error(GL_OUT_OF_MEMORY, false);
    150 		}
    151 	}
    152 
    153 	mWidth = backBufferWidth;
    154 	mHeight = backBufferHeight;
    155 
    156 	return true;
    157 }
    158 
    159 void Surface::swap()
    160 {
    161 	if(backBuffer)
    162 	{
    163 		frameBuffer->flip(backBuffer);
    164 
    165 		checkForResize();
    166 	}
    167 }
    168 
    169 Image *Surface::getRenderTarget()
    170 {
    171 	if(backBuffer)
    172 	{
    173 		backBuffer->addRef();
    174 	}
    175 
    176 	return backBuffer;
    177 }
    178 
    179 Image *Surface::getDepthStencil()
    180 {
    181 	if(mDepthStencil)
    182 	{
    183 		mDepthStencil->addRef();
    184 	}
    185 
    186 	return mDepthStencil;
    187 }
    188 
    189 void Surface::setSwapInterval(GLint interval)
    190 {
    191 	if(mSwapInterval == interval)
    192 	{
    193 		return;
    194 	}
    195 
    196 	mSwapInterval = interval;
    197 	mSwapInterval = std::max(mSwapInterval, mDisplay->getMinSwapInterval());
    198 	mSwapInterval = std::min(mSwapInterval, mDisplay->getMaxSwapInterval());
    199 }
    200 
    201 GLint Surface::getWidth() const
    202 {
    203 	return mWidth;
    204 }
    205 
    206 GLint Surface::getHeight() const
    207 {
    208 	return mHeight;
    209 }
    210 
    211 GLenum Surface::getTextureFormat() const
    212 {
    213 	return mTextureFormat;
    214 }
    215 
    216 GLenum Surface::getTextureTarget() const
    217 {
    218 	return mTextureTarget;
    219 }
    220 
    221 bool Surface::checkForResize()
    222 {
    223 	#if defined(_WIN32)
    224 		RECT client;
    225 		if(!GetClientRect(mWindow, &client))
    226 		{
    227 			ASSERT(false);
    228 			return false;
    229 		}
    230 
    231 		int clientWidth = client.right - client.left;
    232 		int clientHeight = client.bottom - client.top;
    233 	#else
    234 		XWindowAttributes windowAttributes;
    235 		XGetWindowAttributes(mDisplay->getNativeDisplay(), mWindow, &windowAttributes);
    236 
    237 		int clientWidth = windowAttributes.width;
    238 		int clientHeight = windowAttributes.height;
    239 	#endif
    240 
    241 	bool sizeDirty = clientWidth != getWidth() || clientHeight != getHeight();
    242 
    243 	if(sizeDirty)
    244 	{
    245 		reset(clientWidth, clientHeight);
    246 
    247 		if(getCurrentDrawSurface() == this)
    248 		{
    249 			getContext()->makeCurrent(this);
    250 		}
    251 
    252 		return true;
    253 	}
    254 
    255 	return false;
    256 }
    257 }
    258