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
Surface(Display * display,NativeWindowType window)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
Surface(Display * display,GLint width,GLint height,GLenum textureFormat,GLenum textureType)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
~Surface()65 Surface::~Surface()
66 {
67 release();
68 }
69
initialize()70 bool Surface::initialize()
71 {
72 ASSERT(!frameBuffer && !backBuffer && !mDepthStencil);
73
74 return reset();
75 }
76
release()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
reset()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
reset(int backBufferWidth,int backBufferHeight)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
swap()159 void Surface::swap()
160 {
161 if(backBuffer)
162 {
163 frameBuffer->flip(backBuffer);
164
165 checkForResize();
166 }
167 }
168
getRenderTarget()169 Image *Surface::getRenderTarget()
170 {
171 if(backBuffer)
172 {
173 backBuffer->addRef();
174 }
175
176 return backBuffer;
177 }
178
getDepthStencil()179 Image *Surface::getDepthStencil()
180 {
181 if(mDepthStencil)
182 {
183 mDepthStencil->addRef();
184 }
185
186 return mDepthStencil;
187 }
188
setSwapInterval(GLint interval)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
getWidth() const201 GLint Surface::getWidth() const
202 {
203 return mWidth;
204 }
205
getHeight() const206 GLint Surface::getHeight() const
207 {
208 return mHeight;
209 }
210
getTextureFormat() const211 GLenum Surface::getTextureFormat() const
212 {
213 return mTextureFormat;
214 }
215
getTextureTarget() const216 GLenum Surface::getTextureTarget() const
217 {
218 return mTextureTarget;
219 }
220
checkForResize()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