/*-------------------------------------------------------------------------
* drawElements Quality Program OpenGL ES Utilities
* ------------------------------------------------
*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief OpenGL ES context wrapper that uses FBO as default framebuffer.
*//*--------------------------------------------------------------------*/
#include "gluFboRenderContext.hpp"
#include "gluContextFactory.hpp"
#include "gluRenderConfig.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "tcuCommandLine.hpp"
#include "gluTextureUtil.hpp"
#include "tcuTextureUtil.hpp"
#include <sstream>
namespace glu
{
static int getNumDepthBits (const tcu::TextureFormat& format)
{
if (format.order == tcu::TextureFormat::DS)
{
const tcu::TextureFormat depthOnlyFormat = tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_DEPTH);
return tcu::getTextureFormatBitDepth(depthOnlyFormat).x();
}
else if (format.order == tcu::TextureFormat::D)
return tcu::getTextureFormatBitDepth(format).x();
else
return 0;
}
static int getNumStencilBits (const tcu::TextureFormat& format)
{
if (format.order == tcu::TextureFormat::DS)
{
const tcu::TextureFormat stencilOnlyFormat = tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_STENCIL);
return tcu::getTextureFormatBitDepth(stencilOnlyFormat).x();
}
else if (format.order == tcu::TextureFormat::S)
return tcu::getTextureFormatBitDepth(format).x();
else
return 0;
}
static tcu::PixelFormat getPixelFormat (deUint32 colorFormat)
{
const tcu::IVec4 bits = tcu::getTextureFormatBitDepth(glu::mapGLInternalFormat(colorFormat));
return tcu::PixelFormat(bits[0], bits[1], bits[2], bits[3]);
}
static void getDepthStencilBits (deUint32 depthStencilFormat, int* depthBits, int* stencilBits)
{
const tcu::TextureFormat combinedFormat = glu::mapGLInternalFormat(depthStencilFormat);
*depthBits = getNumDepthBits(combinedFormat);
*stencilBits = getNumStencilBits(combinedFormat);
}
deUint32 chooseColorFormat (const glu::RenderConfig& config)
{
static const deUint32 s_formats[] =
{
GL_RGBA8,
GL_RGB8,
GL_RG8,
GL_R8,
GL_RGBA4,
GL_RGB5_A1,
GL_RGB565,
GL_RGB5
};
for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(s_formats); fmtNdx++)
{
const deUint32 format = s_formats[fmtNdx];
const tcu::IVec4 bits = tcu::getTextureFormatBitDepth(glu::mapGLInternalFormat(format));
if (config.redBits != glu::RenderConfig::DONT_CARE &&
config.redBits != bits[0])
continue;
if (config.greenBits != glu::RenderConfig::DONT_CARE &&
config.greenBits != bits[1])
continue;
if (config.blueBits != glu::RenderConfig::DONT_CARE &&
config.blueBits != bits[2])
continue;
if (config.alphaBits != glu::RenderConfig::DONT_CARE &&
config.alphaBits != bits[3])
continue;
return format;
}
return 0;
}
deUint32 chooseDepthStencilFormat (const glu::RenderConfig& config)
{
static const deUint32 s_formats[] =
{
GL_DEPTH32F_STENCIL8,
GL_DEPTH24_STENCIL8,
GL_DEPTH_COMPONENT32F,
GL_DEPTH_COMPONENT24,
GL_DEPTH_COMPONENT16,
GL_STENCIL_INDEX8
};
for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(s_formats); fmtNdx++)
{
const deUint32 format = s_formats[fmtNdx];
const tcu::TextureFormat combinedFormat = glu::mapGLInternalFormat(format);
const int depthBits = getNumDepthBits(combinedFormat);
const int stencilBits = getNumStencilBits(combinedFormat);
if (config.depthBits != glu::RenderConfig::DONT_CARE &&
config.depthBits != depthBits)
continue;
if (config.stencilBits != glu::RenderConfig::DONT_CARE &&
config.stencilBits != stencilBits)
continue;
return format;
}
return 0;
}
FboRenderContext::FboRenderContext (RenderContext* context, const RenderConfig& config)
: m_context (context)
, m_framebuffer (0)
, m_colorBuffer (0)
, m_depthStencilBuffer (0)
, m_renderTarget ()
{
try
{
createFramebuffer(config);
}
catch (...)
{
destroyFramebuffer();
throw;
}
}
FboRenderContext::FboRenderContext (const ContextFactory& factory, const RenderConfig& config, const tcu::CommandLine& cmdLine)
: m_context (DE_NULL)
, m_framebuffer (0)
, m_colorBuffer (0)
, m_depthStencilBuffer (0)
, m_renderTarget ()
{
try
{
RenderConfig nativeRenderConfig;
nativeRenderConfig.type = config.type;
nativeRenderConfig.windowVisibility = config.windowVisibility;
// \note All other properties are defaults, mostly DONT_CARE
m_context = factory.createContext(nativeRenderConfig, cmdLine);
createFramebuffer(config);
}
catch (...)
{
delete m_context;
throw;
}
}
FboRenderContext::~FboRenderContext (void)
{
// \todo [2013-04-08 pyry] Do we want to destry FBO before destroying context?
delete m_context;
}
void FboRenderContext::postIterate (void)
{
// \todo [2012-11-27 pyry] Blit to default framebuffer in ES3?
m_context->getFunctions().finish();
}
void FboRenderContext::makeCurrent(void)
{
m_context->makeCurrent();
}
void FboRenderContext::createFramebuffer (const RenderConfig& config)
{
DE_ASSERT(m_framebuffer == 0 && m_colorBuffer == 0 && m_depthStencilBuffer == 0);
const glw::Functions& gl = m_context->getFunctions();
const deUint32 colorFormat = chooseColorFormat(config);
const deUint32 depthStencilFormat = chooseDepthStencilFormat(config);
int width = config.width;
int height = config.height;
tcu::PixelFormat pixelFormat;
int depthBits = 0;
int stencilBits = 0;
if (config.numSamples > 0 && !gl.renderbufferStorageMultisample)
throw tcu::NotSupportedError("Multisample FBO is not supported");
if (colorFormat == 0)
throw tcu::NotSupportedError("Unsupported color attachment format");
if (width == glu::RenderConfig::DONT_CARE || height == glu::RenderConfig::DONT_CARE)
{
int maxSize = 0;
gl.getIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxSize);
width = (width == glu::RenderConfig::DONT_CARE) ? maxSize : width;
height = (height == glu::RenderConfig::DONT_CARE) ? maxSize : height;
}
{
pixelFormat = getPixelFormat(colorFormat);
gl.genRenderbuffers(1, &m_colorBuffer);
gl.bindRenderbuffer(GL_RENDERBUFFER, m_colorBuffer);
if (config.numSamples > 0)
gl.renderbufferStorageMultisample(GL_RENDERBUFFER, config.numSamples, colorFormat, width, height);
else
gl.renderbufferStorage(GL_RENDERBUFFER, colorFormat, width, height);
gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "Creating color renderbuffer");
}
if (depthStencilFormat != GL_NONE)
{
getDepthStencilBits(depthStencilFormat, &depthBits, &stencilBits);
gl.genRenderbuffers(1, &m_depthStencilBuffer);
gl.bindRenderbuffer(GL_RENDERBUFFER, m_depthStencilBuffer);
if (config.numSamples > 0)
gl.renderbufferStorageMultisample(GL_RENDERBUFFER, config.numSamples, depthStencilFormat, width, height);
else
gl.renderbufferStorage(GL_RENDERBUFFER, depthStencilFormat, width, height);
gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "Creating depth / stencil renderbuffer");
}
gl.genFramebuffers(1, &m_framebuffer);
gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
if (m_colorBuffer)
gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorBuffer);
if (m_depthStencilBuffer)
{
if (depthBits > 0)
gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
if (stencilBits > 0)
gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
}
GLU_EXPECT_NO_ERROR(gl.getError(), "Creating framebuffer");
if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
throw tcu::NotSupportedError("Framebuffer is not complete");
// Set up correct viewport for first test case.
gl.viewport(0, 0, width, height);
m_renderTarget = tcu::RenderTarget(width, height, pixelFormat, depthBits, stencilBits, config.numSamples);
}
void FboRenderContext::destroyFramebuffer (void)
{
const glw::Functions& gl = m_context->getFunctions();
if (m_framebuffer)
{
gl.deleteFramebuffers(1, &m_framebuffer);
m_framebuffer = 0;
}
if (m_depthStencilBuffer)
{
gl.deleteRenderbuffers(1, &m_depthStencilBuffer);
m_depthStencilBuffer = 0;
}
if (m_colorBuffer)
{
gl.deleteRenderbuffers(1, &m_colorBuffer);
m_colorBuffer = 0;
}
}
} // glu