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 =
43 tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_DEPTH);
44 return tcu::getTextureFormatBitDepth(depthOnlyFormat).x();
45 }
46 else if (format.order == tcu::TextureFormat::D)
47 return tcu::getTextureFormatBitDepth(format).x();
48 else
49 return 0;
50 }
51
getNumStencilBits(const tcu::TextureFormat & format)52 static int getNumStencilBits(const tcu::TextureFormat &format)
53 {
54 if (format.order == tcu::TextureFormat::DS)
55 {
56 const tcu::TextureFormat stencilOnlyFormat =
57 tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_STENCIL);
58 return tcu::getTextureFormatBitDepth(stencilOnlyFormat).x();
59 }
60 else if (format.order == tcu::TextureFormat::S)
61 return tcu::getTextureFormatBitDepth(format).x();
62 else
63 return 0;
64 }
65
getPixelFormat(uint32_t colorFormat)66 static tcu::PixelFormat getPixelFormat(uint32_t colorFormat)
67 {
68 const tcu::IVec4 bits = tcu::getTextureFormatBitDepth(glu::mapGLInternalFormat(colorFormat));
69 return tcu::PixelFormat(bits[0], bits[1], bits[2], bits[3]);
70 }
71
getDepthStencilBits(uint32_t depthStencilFormat,int * depthBits,int * stencilBits)72 static void getDepthStencilBits(uint32_t depthStencilFormat, int *depthBits, int *stencilBits)
73 {
74 const tcu::TextureFormat combinedFormat = glu::mapGLInternalFormat(depthStencilFormat);
75
76 *depthBits = getNumDepthBits(combinedFormat);
77 *stencilBits = getNumStencilBits(combinedFormat);
78 }
79
chooseColorFormat(const glu::RenderConfig & config)80 uint32_t chooseColorFormat(const glu::RenderConfig &config)
81 {
82 static const uint32_t s_formats[] = {GL_RGBA8, GL_RGB8, GL_RG8, GL_R8, GL_RGBA4, GL_RGB5_A1, GL_RGB565, GL_RGB5};
83
84 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(s_formats); fmtNdx++)
85 {
86 const uint32_t format = s_formats[fmtNdx];
87 const tcu::IVec4 bits = tcu::getTextureFormatBitDepth(glu::mapGLInternalFormat(format));
88
89 if (config.redBits != glu::RenderConfig::DONT_CARE && config.redBits != bits[0])
90 continue;
91
92 if (config.greenBits != glu::RenderConfig::DONT_CARE && config.greenBits != bits[1])
93 continue;
94
95 if (config.blueBits != glu::RenderConfig::DONT_CARE && config.blueBits != bits[2])
96 continue;
97
98 if (config.alphaBits != glu::RenderConfig::DONT_CARE && config.alphaBits != bits[3])
99 continue;
100
101 return format;
102 }
103
104 return 0;
105 }
106
chooseDepthStencilFormat(const glu::RenderConfig & config)107 uint32_t chooseDepthStencilFormat(const glu::RenderConfig &config)
108 {
109 static const uint32_t s_formats[] = {GL_DEPTH32F_STENCIL8, GL_DEPTH24_STENCIL8, GL_DEPTH_COMPONENT32F,
110 GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT16, GL_STENCIL_INDEX8};
111
112 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(s_formats); fmtNdx++)
113 {
114 const uint32_t format = s_formats[fmtNdx];
115 const tcu::TextureFormat combinedFormat = glu::mapGLInternalFormat(format);
116 const int depthBits = getNumDepthBits(combinedFormat);
117 const int stencilBits = getNumStencilBits(combinedFormat);
118
119 if (config.depthBits != glu::RenderConfig::DONT_CARE && config.depthBits != depthBits)
120 continue;
121
122 if (config.stencilBits != glu::RenderConfig::DONT_CARE && config.stencilBits != stencilBits)
123 continue;
124
125 return format;
126 }
127
128 return 0;
129 }
130
FboRenderContext(RenderContext * context,const RenderConfig & config)131 FboRenderContext::FboRenderContext(RenderContext *context, const RenderConfig &config)
132 : m_context(context)
133 , m_framebuffer(0)
134 , m_colorBuffer(0)
135 , m_depthStencilBuffer(0)
136 , m_renderTarget()
137 {
138 try
139 {
140 createFramebuffer(config);
141 }
142 catch (...)
143 {
144 destroyFramebuffer();
145 throw;
146 }
147 }
148
FboRenderContext(const ContextFactory & factory,const RenderConfig & config,const tcu::CommandLine & cmdLine)149 FboRenderContext::FboRenderContext(const ContextFactory &factory, const RenderConfig &config,
150 const tcu::CommandLine &cmdLine)
151 : m_context(DE_NULL)
152 , m_framebuffer(0)
153 , m_colorBuffer(0)
154 , m_depthStencilBuffer(0)
155 , m_renderTarget()
156 {
157 try
158 {
159 RenderConfig nativeRenderConfig;
160 nativeRenderConfig.type = config.type;
161 nativeRenderConfig.windowVisibility = config.windowVisibility;
162 // \note All other properties are defaults, mostly DONT_CARE
163 m_context = factory.createContext(nativeRenderConfig, cmdLine, DE_NULL);
164 createFramebuffer(config);
165 }
166 catch (...)
167 {
168 delete m_context;
169 throw;
170 }
171 }
172
~FboRenderContext(void)173 FboRenderContext::~FboRenderContext(void)
174 {
175 // \todo [2013-04-08 pyry] Do we want to destry FBO before destroying context?
176 delete m_context;
177 }
178
postIterate(void)179 void FboRenderContext::postIterate(void)
180 {
181 // \todo [2012-11-27 pyry] Blit to default framebuffer in ES3?
182 m_context->getFunctions().finish();
183 }
184
makeCurrent(void)185 void FboRenderContext::makeCurrent(void)
186 {
187 m_context->makeCurrent();
188 }
189
createFramebuffer(const RenderConfig & config)190 void FboRenderContext::createFramebuffer(const RenderConfig &config)
191 {
192 DE_ASSERT(m_framebuffer == 0 && m_colorBuffer == 0 && m_depthStencilBuffer == 0);
193
194 const glw::Functions &gl = m_context->getFunctions();
195 const uint32_t colorFormat = chooseColorFormat(config);
196 const uint32_t depthStencilFormat = chooseDepthStencilFormat(config);
197 int width = config.width;
198 int height = config.height;
199 tcu::PixelFormat pixelFormat;
200 int depthBits = 0;
201 int stencilBits = 0;
202
203 if (config.numSamples > 0 && !gl.renderbufferStorageMultisample)
204 throw tcu::NotSupportedError("Multisample FBO is not supported");
205
206 if (colorFormat == 0)
207 throw tcu::NotSupportedError("Unsupported color attachment format");
208
209 if (width == glu::RenderConfig::DONT_CARE || height == glu::RenderConfig::DONT_CARE)
210 {
211 int maxSize = 0;
212 gl.getIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxSize);
213
214 width = (width == glu::RenderConfig::DONT_CARE) ? maxSize : width;
215 height = (height == glu::RenderConfig::DONT_CARE) ? maxSize : height;
216 }
217
218 {
219 pixelFormat = getPixelFormat(colorFormat);
220
221 gl.genRenderbuffers(1, &m_colorBuffer);
222 gl.bindRenderbuffer(GL_RENDERBUFFER, m_colorBuffer);
223
224 if (config.numSamples > 0)
225 gl.renderbufferStorageMultisample(GL_RENDERBUFFER, config.numSamples, colorFormat, width, height);
226 else
227 gl.renderbufferStorage(GL_RENDERBUFFER, colorFormat, width, height);
228
229 gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
230 GLU_EXPECT_NO_ERROR(gl.getError(), "Creating color renderbuffer");
231 }
232
233 if (depthStencilFormat != GL_NONE)
234 {
235 getDepthStencilBits(depthStencilFormat, &depthBits, &stencilBits);
236
237 gl.genRenderbuffers(1, &m_depthStencilBuffer);
238 gl.bindRenderbuffer(GL_RENDERBUFFER, m_depthStencilBuffer);
239
240 if (config.numSamples > 0)
241 gl.renderbufferStorageMultisample(GL_RENDERBUFFER, config.numSamples, depthStencilFormat, width, height);
242 else
243 gl.renderbufferStorage(GL_RENDERBUFFER, depthStencilFormat, width, height);
244
245 gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
246 GLU_EXPECT_NO_ERROR(gl.getError(), "Creating depth / stencil renderbuffer");
247 }
248
249 gl.genFramebuffers(1, &m_framebuffer);
250 gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
251
252 if (m_colorBuffer)
253 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorBuffer);
254
255 if (m_depthStencilBuffer)
256 {
257 if (depthBits > 0)
258 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
259
260 if (stencilBits > 0)
261 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
262 }
263
264 GLU_EXPECT_NO_ERROR(gl.getError(), "Creating framebuffer");
265
266 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
267 throw tcu::NotSupportedError("Framebuffer is not complete");
268
269 // Set up correct viewport for first test case.
270 gl.viewport(0, 0, width, height);
271
272 m_renderTarget = tcu::RenderTarget(width, height, pixelFormat, depthBits, stencilBits, config.numSamples);
273 }
274
destroyFramebuffer(void)275 void FboRenderContext::destroyFramebuffer(void)
276 {
277 const glw::Functions &gl = m_context->getFunctions();
278
279 if (m_framebuffer)
280 {
281 gl.deleteFramebuffers(1, &m_framebuffer);
282 m_framebuffer = 0;
283 }
284
285 if (m_depthStencilBuffer)
286 {
287 gl.deleteRenderbuffers(1, &m_depthStencilBuffer);
288 m_depthStencilBuffer = 0;
289 }
290
291 if (m_colorBuffer)
292 {
293 gl.deleteRenderbuffers(1, &m_colorBuffer);
294 m_colorBuffer = 0;
295 }
296 }
297
298 } // namespace glu
299