You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
319 lines
8.8 KiB
319 lines
8.8 KiB
/*-------------------------------------------------------------------------
|
|
* 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, DE_NULL);
|
|
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
|