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 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
getRenderTarget()171 Image *Surface::getRenderTarget()
172 {
173 if(backBuffer)
174 {
175 backBuffer->addRef();
176 }
177
178 return backBuffer;
179 }
180
getDepthStencil()181 Image *Surface::getDepthStencil()
182 {
183 if(mDepthStencil)
184 {
185 mDepthStencil->addRef();
186 }
187
188 return mDepthStencil;
189 }
190
setSwapInterval(GLint interval)191 void 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
getWidth() const203 GLint Surface::getWidth() const
204 {
205 return mWidth;
206 }
207
getHeight() const208 GLint Surface::getHeight() const
209 {
210 return mHeight;
211 }
212
getTextureFormat() const213 GLenum Surface::getTextureFormat() const
214 {
215 return mTextureFormat;
216 }
217
getTextureTarget() const218 GLenum Surface::getTextureTarget() const
219 {
220 return mTextureTarget;
221 }
222
checkForResize()223 bool 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