1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES Utilities
3 * ------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief OpenGL ES context wrapper that uses FBO as default framebuffer.
22 *//*--------------------------------------------------------------------*/
23
24 #include "gluFboRenderContext.hpp"
25 #include "gluContextFactory.hpp"
26 #include "gluRenderConfig.hpp"
27 #include "glwEnums.hpp"
28 #include "glwFunctions.hpp"
29 #include "tcuCommandLine.hpp"
30 #include "gluTextureUtil.hpp"
31 #include "tcuTextureUtil.hpp"
32
33 #include <sstream>
34
35 namespace glu
36 {
37
getNumDepthBits(const tcu::TextureFormat & format)38 static int getNumDepthBits (const tcu::TextureFormat& format)
39 {
40 if (format.order == tcu::TextureFormat::DS)
41 {
42 const tcu::TextureFormat depthOnlyFormat = tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_DEPTH);
43 return tcu::getTextureFormatBitDepth(depthOnlyFormat).x();
44 }
45 else if (format.order == tcu::TextureFormat::D)
46 return tcu::getTextureFormatBitDepth(format).x();
47 else
48 return 0;
49 }
50
getNumStencilBits(const tcu::TextureFormat & format)51 static int getNumStencilBits (const tcu::TextureFormat& format)
52 {
53 if (format.order == tcu::TextureFormat::DS)
54 {
55 const tcu::TextureFormat stencilOnlyFormat = tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_STENCIL);
56 return tcu::getTextureFormatBitDepth(stencilOnlyFormat).x();
57 }
58 else if (format.order == tcu::TextureFormat::S)
59 return tcu::getTextureFormatBitDepth(format).x();
60 else
61 return 0;
62 }
63
getPixelFormat(deUint32 colorFormat)64 static tcu::PixelFormat getPixelFormat (deUint32 colorFormat)
65 {
66 const tcu::IVec4 bits = tcu::getTextureFormatBitDepth(glu::mapGLInternalFormat(colorFormat));
67 return tcu::PixelFormat(bits[0], bits[1], bits[2], bits[3]);
68 }
69
getDepthStencilBits(deUint32 depthStencilFormat,int * depthBits,int * stencilBits)70 static void getDepthStencilBits (deUint32 depthStencilFormat, int* depthBits, int* stencilBits)
71 {
72 const tcu::TextureFormat combinedFormat = glu::mapGLInternalFormat(depthStencilFormat);
73
74 *depthBits = getNumDepthBits(combinedFormat);
75 *stencilBits = getNumStencilBits(combinedFormat);
76 }
77
chooseColorFormat(const glu::RenderConfig & config)78 deUint32 chooseColorFormat (const glu::RenderConfig& config)
79 {
80 static const deUint32 s_formats[] =
81 {
82 GL_RGBA8,
83 GL_RGB8,
84 GL_RG8,
85 GL_R8,
86 GL_RGBA4,
87 GL_RGB5_A1,
88 GL_RGB565,
89 GL_RGB5
90 };
91
92 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(s_formats); fmtNdx++)
93 {
94 const deUint32 format = s_formats[fmtNdx];
95 const tcu::IVec4 bits = tcu::getTextureFormatBitDepth(glu::mapGLInternalFormat(format));
96
97 if (config.redBits != glu::RenderConfig::DONT_CARE &&
98 config.redBits != bits[0])
99 continue;
100
101 if (config.greenBits != glu::RenderConfig::DONT_CARE &&
102 config.greenBits != bits[1])
103 continue;
104
105 if (config.blueBits != glu::RenderConfig::DONT_CARE &&
106 config.blueBits != bits[2])
107 continue;
108
109 if (config.alphaBits != glu::RenderConfig::DONT_CARE &&
110 config.alphaBits != bits[3])
111 continue;
112
113 return format;
114 }
115
116 return 0;
117 }
118
chooseDepthStencilFormat(const glu::RenderConfig & config)119 deUint32 chooseDepthStencilFormat (const glu::RenderConfig& config)
120 {
121 static const deUint32 s_formats[] =
122 {
123 GL_DEPTH32F_STENCIL8,
124 GL_DEPTH24_STENCIL8,
125 GL_DEPTH_COMPONENT32F,
126 GL_DEPTH_COMPONENT24,
127 GL_DEPTH_COMPONENT16,
128 GL_STENCIL_INDEX8
129 };
130
131 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(s_formats); fmtNdx++)
132 {
133 const deUint32 format = s_formats[fmtNdx];
134 const tcu::TextureFormat combinedFormat = glu::mapGLInternalFormat(format);
135 const int depthBits = getNumDepthBits(combinedFormat);
136 const int stencilBits = getNumStencilBits(combinedFormat);
137
138 if (config.depthBits != glu::RenderConfig::DONT_CARE &&
139 config.depthBits != depthBits)
140 continue;
141
142 if (config.stencilBits != glu::RenderConfig::DONT_CARE &&
143 config.stencilBits != stencilBits)
144 continue;
145
146 return format;
147 }
148
149 return 0;
150 }
151
FboRenderContext(RenderContext * context,const RenderConfig & config)152 FboRenderContext::FboRenderContext (RenderContext* context, const RenderConfig& config)
153 : m_context (context)
154 , m_framebuffer (0)
155 , m_colorBuffer (0)
156 , m_depthStencilBuffer (0)
157 , m_renderTarget ()
158 {
159 try
160 {
161 createFramebuffer(config);
162 }
163 catch (...)
164 {
165 destroyFramebuffer();
166 throw;
167 }
168 }
169
FboRenderContext(const ContextFactory & factory,const RenderConfig & config,const tcu::CommandLine & cmdLine)170 FboRenderContext::FboRenderContext (const ContextFactory& factory, const RenderConfig& config, const tcu::CommandLine& cmdLine)
171 : m_context (DE_NULL)
172 , m_framebuffer (0)
173 , m_colorBuffer (0)
174 , m_depthStencilBuffer (0)
175 , m_renderTarget ()
176 {
177 try
178 {
179 RenderConfig nativeRenderConfig;
180 nativeRenderConfig.type = config.type;
181 nativeRenderConfig.windowVisibility = config.windowVisibility;
182 // \note All other properties are defaults, mostly DONT_CARE
183 m_context = factory.createContext(nativeRenderConfig, cmdLine, DE_NULL);
184 createFramebuffer(config);
185 }
186 catch (...)
187 {
188 delete m_context;
189 throw;
190 }
191 }
192
~FboRenderContext(void)193 FboRenderContext::~FboRenderContext (void)
194 {
195 // \todo [2013-04-08 pyry] Do we want to destry FBO before destroying context?
196 delete m_context;
197 }
198
postIterate(void)199 void FboRenderContext::postIterate (void)
200 {
201 // \todo [2012-11-27 pyry] Blit to default framebuffer in ES3?
202 m_context->getFunctions().finish();
203 }
204
makeCurrent(void)205 void FboRenderContext::makeCurrent(void)
206 {
207 m_context->makeCurrent();
208 }
209
createFramebuffer(const RenderConfig & config)210 void FboRenderContext::createFramebuffer (const RenderConfig& config)
211 {
212 DE_ASSERT(m_framebuffer == 0 && m_colorBuffer == 0 && m_depthStencilBuffer == 0);
213
214 const glw::Functions& gl = m_context->getFunctions();
215 const deUint32 colorFormat = chooseColorFormat(config);
216 const deUint32 depthStencilFormat = chooseDepthStencilFormat(config);
217 int width = config.width;
218 int height = config.height;
219 tcu::PixelFormat pixelFormat;
220 int depthBits = 0;
221 int stencilBits = 0;
222
223 if (config.numSamples > 0 && !gl.renderbufferStorageMultisample)
224 throw tcu::NotSupportedError("Multisample FBO is not supported");
225
226 if (colorFormat == 0)
227 throw tcu::NotSupportedError("Unsupported color attachment format");
228
229 if (width == glu::RenderConfig::DONT_CARE || height == glu::RenderConfig::DONT_CARE)
230 {
231 int maxSize = 0;
232 gl.getIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxSize);
233
234 width = (width == glu::RenderConfig::DONT_CARE) ? maxSize : width;
235 height = (height == glu::RenderConfig::DONT_CARE) ? maxSize : height;
236 }
237
238 {
239 pixelFormat = getPixelFormat(colorFormat);
240
241 gl.genRenderbuffers(1, &m_colorBuffer);
242 gl.bindRenderbuffer(GL_RENDERBUFFER, m_colorBuffer);
243
244 if (config.numSamples > 0)
245 gl.renderbufferStorageMultisample(GL_RENDERBUFFER, config.numSamples, colorFormat, width, height);
246 else
247 gl.renderbufferStorage(GL_RENDERBUFFER, colorFormat, width, height);
248
249 gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
250 GLU_EXPECT_NO_ERROR(gl.getError(), "Creating color renderbuffer");
251 }
252
253 if (depthStencilFormat != GL_NONE)
254 {
255 getDepthStencilBits(depthStencilFormat, &depthBits, &stencilBits);
256
257 gl.genRenderbuffers(1, &m_depthStencilBuffer);
258 gl.bindRenderbuffer(GL_RENDERBUFFER, m_depthStencilBuffer);
259
260 if (config.numSamples > 0)
261 gl.renderbufferStorageMultisample(GL_RENDERBUFFER, config.numSamples, depthStencilFormat, width, height);
262 else
263 gl.renderbufferStorage(GL_RENDERBUFFER, depthStencilFormat, width, height);
264
265 gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
266 GLU_EXPECT_NO_ERROR(gl.getError(), "Creating depth / stencil renderbuffer");
267 }
268
269 gl.genFramebuffers(1, &m_framebuffer);
270 gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
271
272 if (m_colorBuffer)
273 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorBuffer);
274
275 if (m_depthStencilBuffer)
276 {
277 if (depthBits > 0)
278 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
279
280 if (stencilBits > 0)
281 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
282 }
283
284 GLU_EXPECT_NO_ERROR(gl.getError(), "Creating framebuffer");
285
286 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
287 throw tcu::NotSupportedError("Framebuffer is not complete");
288
289 // Set up correct viewport for first test case.
290 gl.viewport(0, 0, width, height);
291
292 m_renderTarget = tcu::RenderTarget(width, height, pixelFormat, depthBits, stencilBits, config.numSamples);
293 }
294
destroyFramebuffer(void)295 void FboRenderContext::destroyFramebuffer (void)
296 {
297 const glw::Functions& gl = m_context->getFunctions();
298
299 if (m_framebuffer)
300 {
301 gl.deleteFramebuffers(1, &m_framebuffer);
302 m_framebuffer = 0;
303 }
304
305 if (m_depthStencilBuffer)
306 {
307 gl.deleteRenderbuffers(1, &m_depthStencilBuffer);
308 m_depthStencilBuffer = 0;
309 }
310
311 if (m_colorBuffer)
312 {
313 gl.deleteRenderbuffers(1, &m_colorBuffer);
314 m_colorBuffer = 0;
315 }
316 }
317
318 } // glu
319