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 33namespace gl 34{ 35 36Surface::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 50Surface::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 65Surface::~Surface() 66{ 67 release(); 68} 69 70bool Surface::initialize() 71{ 72 ASSERT(!frameBuffer && !backBuffer && !mDepthStencil); 73 74 return reset(); 75} 76 77void 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 95bool 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 116bool 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 159void Surface::swap() 160{ 161 if(backBuffer) 162 { 163 void *source = backBuffer->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC); 164 frameBuffer->flip(source, backBuffer->Surface::getInternalFormat(), backBuffer->getInternalPitchB()); 165 backBuffer->unlockInternal(); 166 167 checkForResize(); 168 } 169} 170 171Image *Surface::getRenderTarget() 172{ 173 if(backBuffer) 174 { 175 backBuffer->addRef(); 176 } 177 178 return backBuffer; 179} 180 181Image *Surface::getDepthStencil() 182{ 183 if(mDepthStencil) 184 { 185 mDepthStencil->addRef(); 186 } 187 188 return mDepthStencil; 189} 190 191void Surface::setSwapInterval(GLint interval) 192{ 193 if(mSwapInterval == interval) 194 { 195 return; 196 } 197 198 mSwapInterval = interval; 199 mSwapInterval = std::max(mSwapInterval, mDisplay->getMinSwapInterval()); 200 mSwapInterval = std::min(mSwapInterval, mDisplay->getMaxSwapInterval()); 201} 202 203GLint Surface::getWidth() const 204{ 205 return mWidth; 206} 207 208GLint Surface::getHeight() const 209{ 210 return mHeight; 211} 212 213GLenum Surface::getTextureFormat() const 214{ 215 return mTextureFormat; 216} 217 218GLenum Surface::getTextureTarget() const 219{ 220 return mTextureTarget; 221} 222 223bool Surface::checkForResize() 224{ 225 #if defined(_WIN32) 226 RECT client; 227 if(!GetClientRect(mWindow, &client)) 228 { 229 ASSERT(false); 230 return false; 231 } 232 233 int clientWidth = client.right - client.left; 234 int clientHeight = client.bottom - client.top; 235 #else 236 XWindowAttributes windowAttributes; 237 XGetWindowAttributes(mDisplay->getNativeDisplay(), mWindow, &windowAttributes); 238 239 int clientWidth = windowAttributes.width; 240 int clientHeight = windowAttributes.height; 241 #endif 242 243 bool sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); 244 245 if(sizeDirty) 246 { 247 reset(clientWidth, clientHeight); 248 249 if(getCurrentDrawSurface() == this) 250 { 251 getContext()->makeCurrent(this); 252 } 253 254 return true; 255 } 256 257 return false; 258} 259} 260