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