636 lines
19 KiB
C++
636 lines
19 KiB
C++
/*-------------------------------------------------------------------------
|
|
* drawElements Quality Program OpenGL (ES) Module
|
|
* -----------------------------------------------
|
|
*
|
|
* 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 Utilities for framebuffer objects.
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "glsFboUtil.hpp"
|
|
|
|
#include "glwEnums.hpp"
|
|
#include "deUniquePtr.hpp"
|
|
#include "gluTextureUtil.hpp"
|
|
#include "gluStrUtil.hpp"
|
|
#include "deStringUtil.hpp"
|
|
#include <sstream>
|
|
|
|
using namespace glw;
|
|
using tcu::TestLog;
|
|
using tcu::TextureFormat;
|
|
using tcu::NotSupportedError;
|
|
using glu::TransferFormat;
|
|
using glu::mapGLInternalFormat;
|
|
using glu::mapGLTransferFormat;
|
|
using glu::getPixelFormatName;
|
|
using glu::getTypeName;
|
|
using glu::getFramebufferTargetName;
|
|
using glu::getFramebufferAttachmentName;
|
|
using glu::getFramebufferAttachmentTypeName;
|
|
using glu::getTextureTargetName;
|
|
using glu::getTransferFormat;
|
|
using glu::ContextInfo;
|
|
using glu::ContextType;
|
|
using glu::RenderContext;
|
|
using de::UniquePtr;
|
|
using de::toString;
|
|
using std::set;
|
|
using std::vector;
|
|
using std::string;
|
|
using std::istringstream;
|
|
using std::istream_iterator;
|
|
|
|
namespace deqp
|
|
{
|
|
namespace gls
|
|
{
|
|
|
|
namespace FboUtil
|
|
{
|
|
|
|
|
|
void FormatDB::addFormat (ImageFormat format, FormatFlags newFlags)
|
|
{
|
|
FormatFlags& flags = m_map[format];
|
|
flags = FormatFlags(flags | newFlags);
|
|
}
|
|
|
|
// Not too fast at the moment, might consider indexing?
|
|
Formats FormatDB::getFormats (FormatFlags requirements) const
|
|
{
|
|
Formats ret;
|
|
for (FormatMap::const_iterator it = m_map.begin(); it != m_map.end(); it++)
|
|
{
|
|
if ((it->second & requirements) == requirements)
|
|
ret.insert(it->first);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
FormatFlags FormatDB::getFormatInfo (ImageFormat format, FormatFlags fallback) const
|
|
{
|
|
return lookupDefault(m_map, format, fallback);
|
|
}
|
|
|
|
void addFormats (FormatDB& db, FormatEntries stdFmts)
|
|
{
|
|
for (const FormatEntry* it = stdFmts.begin(); it != stdFmts.end(); it++)
|
|
{
|
|
for (const FormatKey* it2 = it->second.begin(); it2 != it->second.end(); it2++)
|
|
db.addFormat(formatKeyInfo(*it2), it->first);
|
|
}
|
|
}
|
|
|
|
void addExtFormats (FormatDB& db, FormatExtEntries extFmts, const RenderContext* ctx)
|
|
{
|
|
const UniquePtr<ContextInfo> ctxInfo(ctx != DE_NULL ? ContextInfo::create(*ctx) : DE_NULL);
|
|
for (const FormatExtEntry* it = extFmts.begin(); it != extFmts.end(); it++)
|
|
{
|
|
bool supported = true;
|
|
if (ctxInfo)
|
|
{
|
|
istringstream tokenStream(string(it->extensions));
|
|
istream_iterator<string> tokens((tokenStream)), end;
|
|
|
|
while (tokens != end)
|
|
{
|
|
if (!ctxInfo->isExtensionSupported(tokens->c_str()))
|
|
{
|
|
supported = false;
|
|
break;
|
|
}
|
|
++tokens;
|
|
}
|
|
}
|
|
if (supported)
|
|
for (const FormatKey* i2 = it->formats.begin(); i2 != it->formats.end(); i2++)
|
|
db.addFormat(formatKeyInfo(*i2), FormatFlags(it->flags));
|
|
}
|
|
}
|
|
|
|
FormatFlags formatFlag (GLenum context)
|
|
{
|
|
switch (context)
|
|
{
|
|
case GL_NONE:
|
|
return FormatFlags(0);
|
|
case GL_RENDERBUFFER:
|
|
return RENDERBUFFER_VALID;
|
|
case GL_TEXTURE:
|
|
return TEXTURE_VALID;
|
|
case GL_STENCIL_ATTACHMENT:
|
|
return STENCIL_RENDERABLE;
|
|
case GL_DEPTH_ATTACHMENT:
|
|
return DEPTH_RENDERABLE;
|
|
default:
|
|
DE_ASSERT(context >= GL_COLOR_ATTACHMENT0 && context <= GL_COLOR_ATTACHMENT15);
|
|
return COLOR_RENDERABLE;
|
|
}
|
|
}
|
|
|
|
namespace config {
|
|
|
|
GLsizei imageNumSamples (const Image& img)
|
|
{
|
|
if (const Renderbuffer* rbo = dynamic_cast<const Renderbuffer*>(&img))
|
|
return rbo->numSamples;
|
|
return 0;
|
|
}
|
|
|
|
static GLenum glTarget (const Image& img)
|
|
{
|
|
if (dynamic_cast<const Renderbuffer*>(&img) != DE_NULL)
|
|
return GL_RENDERBUFFER;
|
|
if (dynamic_cast<const Texture2D*>(&img) != DE_NULL)
|
|
return GL_TEXTURE_2D;
|
|
if (dynamic_cast<const TextureCubeMap*>(&img) != DE_NULL)
|
|
return GL_TEXTURE_CUBE_MAP;
|
|
if (dynamic_cast<const Texture3D*>(&img) != DE_NULL)
|
|
return GL_TEXTURE_3D;
|
|
if (dynamic_cast<const Texture2DArray*>(&img) != DE_NULL)
|
|
return GL_TEXTURE_2D_ARRAY;
|
|
|
|
DE_ASSERT(!"Impossible image type");
|
|
return GL_NONE;
|
|
}
|
|
|
|
static void glInitFlat (const TextureFlat& cfg, GLenum target, const glw::Functions& gl)
|
|
{
|
|
const TransferFormat format = transferImageFormat(cfg.internalFormat);
|
|
GLint w = cfg.width;
|
|
GLint h = cfg.height;
|
|
for (GLint level = 0; level < cfg.numLevels; level++)
|
|
{
|
|
gl.texImage2D(target, level, cfg.internalFormat.format, w, h, 0,
|
|
format.format, format.dataType, DE_NULL);
|
|
w = de::max(1, w / 2);
|
|
h = de::max(1, h / 2);
|
|
}
|
|
}
|
|
|
|
static void glInitLayered (const TextureLayered& cfg,
|
|
GLint depth_divider, const glw::Functions& gl)
|
|
{
|
|
const TransferFormat format = transferImageFormat(cfg.internalFormat);
|
|
GLint w = cfg.width;
|
|
GLint h = cfg.height;
|
|
GLint depth = cfg.numLayers;
|
|
for (GLint level = 0; level < cfg.numLevels; level++)
|
|
{
|
|
gl.texImage3D(glTarget(cfg), level, cfg.internalFormat.format, w, h, depth, 0,
|
|
format.format, format.dataType, DE_NULL);
|
|
w = de::max(1, w / 2);
|
|
h = de::max(1, h / 2);
|
|
depth = de::max(1, depth / depth_divider);
|
|
}
|
|
}
|
|
|
|
static void glInit (const Texture& cfg, const glw::Functions& gl)
|
|
{
|
|
if (const Texture2D* t2d = dynamic_cast<const Texture2D*>(&cfg))
|
|
glInitFlat(*t2d, glTarget(*t2d), gl);
|
|
else if (const TextureCubeMap* tcm = dynamic_cast<const TextureCubeMap*>(&cfg))
|
|
{
|
|
// \todo [2013-12-05 lauri]
|
|
// move this to glu or someplace sensible (this array is already
|
|
// present in duplicates)
|
|
static const GLenum s_cubeMapFaces[] =
|
|
{
|
|
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
|
|
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
|
|
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
|
GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
|
|
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
|
|
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
|
|
};
|
|
const Range<GLenum> range = GLS_ARRAY_RANGE(s_cubeMapFaces);
|
|
for (const GLenum* it = range.begin(); it != range.end(); it++)
|
|
glInitFlat(*tcm, *it, gl);
|
|
}
|
|
else if (const Texture3D* t3d = dynamic_cast<const Texture3D*>(&cfg))
|
|
glInitLayered(*t3d, 2, gl);
|
|
else if (const Texture2DArray* t2a = dynamic_cast<const Texture2DArray*>(&cfg))
|
|
glInitLayered(*t2a, 1, gl);
|
|
}
|
|
|
|
static GLuint glCreate (const Image& cfg, const glw::Functions& gl)
|
|
{
|
|
GLuint ret = 0;
|
|
if (const Renderbuffer* const rbo = dynamic_cast<const Renderbuffer*>(&cfg))
|
|
{
|
|
gl.genRenderbuffers(1, &ret);
|
|
gl.bindRenderbuffer(GL_RENDERBUFFER, ret);
|
|
|
|
if (rbo->numSamples == 0)
|
|
gl.renderbufferStorage(GL_RENDERBUFFER, rbo->internalFormat.format,
|
|
rbo->width, rbo->height);
|
|
else
|
|
gl.renderbufferStorageMultisample(
|
|
GL_RENDERBUFFER, rbo->numSamples, rbo->internalFormat.format,
|
|
rbo->width, rbo->height);
|
|
|
|
gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
|
|
}
|
|
else if (const Texture* const tex = dynamic_cast<const Texture*>(&cfg))
|
|
{
|
|
gl.genTextures(1, &ret);
|
|
gl.bindTexture(glTarget(*tex), ret);
|
|
glInit(*tex, gl);
|
|
gl.bindTexture(glTarget(*tex), 0);
|
|
}
|
|
else
|
|
DE_ASSERT(!"Impossible image type");
|
|
return ret;
|
|
}
|
|
|
|
static void glDelete (const Image& cfg, GLuint img, const glw::Functions& gl)
|
|
{
|
|
if (dynamic_cast<const Renderbuffer*>(&cfg) != DE_NULL)
|
|
gl.deleteRenderbuffers(1, &img);
|
|
else if (dynamic_cast<const Texture*>(&cfg) != DE_NULL)
|
|
gl.deleteTextures(1, &img);
|
|
else
|
|
DE_ASSERT(!"Impossible image type");
|
|
}
|
|
|
|
static void attachAttachment (const Attachment& att, GLenum attPoint,
|
|
const glw::Functions& gl)
|
|
{
|
|
if (const RenderbufferAttachment* const rAtt =
|
|
dynamic_cast<const RenderbufferAttachment*>(&att))
|
|
gl.framebufferRenderbuffer(rAtt->target, attPoint,
|
|
rAtt->renderbufferTarget, rAtt->imageName);
|
|
else if (const TextureFlatAttachment* const fAtt =
|
|
dynamic_cast<const TextureFlatAttachment*>(&att))
|
|
gl.framebufferTexture2D(fAtt->target, attPoint,
|
|
fAtt->texTarget, fAtt->imageName, fAtt->level);
|
|
else if (const TextureLayerAttachment* const lAtt =
|
|
dynamic_cast<const TextureLayerAttachment*>(&att))
|
|
gl.framebufferTextureLayer(lAtt->target, attPoint,
|
|
lAtt->imageName, lAtt->level, lAtt->layer);
|
|
else
|
|
DE_ASSERT(!"Impossible attachment type");
|
|
}
|
|
|
|
GLenum attachmentType (const Attachment& att)
|
|
{
|
|
if (dynamic_cast<const RenderbufferAttachment*>(&att) != DE_NULL)
|
|
return GL_RENDERBUFFER;
|
|
else if (dynamic_cast<const TextureAttachment*>(&att) != DE_NULL)
|
|
return GL_TEXTURE;
|
|
|
|
DE_ASSERT(!"Impossible attachment type");
|
|
return GL_NONE;
|
|
}
|
|
|
|
static GLsizei textureLayer (const TextureAttachment& tAtt)
|
|
{
|
|
if (dynamic_cast<const TextureFlatAttachment*>(&tAtt) != DE_NULL)
|
|
return 0;
|
|
else if (const TextureLayerAttachment* const lAtt =
|
|
dynamic_cast<const TextureLayerAttachment*>(&tAtt))
|
|
return lAtt->layer;
|
|
|
|
DE_ASSERT(!"Impossible attachment type");
|
|
return 0;
|
|
}
|
|
|
|
static void checkAttachmentCompleteness (Checker& cctx, const Attachment& attachment,
|
|
GLenum attPoint, const Image* image,
|
|
const FormatDB& db)
|
|
{
|
|
// GLES2 4.4.5 / GLES3 4.4.4, "Framebuffer attachment completeness"
|
|
|
|
if (const TextureAttachment* const texAtt =
|
|
dynamic_cast<const TextureAttachment*>(&attachment))
|
|
if (const TextureLayered* const ltex = dynamic_cast<const TextureLayered*>(image))
|
|
{
|
|
// GLES3: "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is
|
|
// TEXTURE and the value of FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names a
|
|
// three-dimensional texture, then the value of
|
|
// FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER must be smaller than the depth
|
|
// of the texture.
|
|
//
|
|
// GLES3: "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is
|
|
// TEXTURE and the value of FRAMEBUFFER_ATTACHMENT_OBJECT_NAME names a
|
|
// two-dimensional array texture, then the value of
|
|
// FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER must be smaller than the
|
|
// number of layers in the texture.
|
|
|
|
cctx.require(textureLayer(*texAtt) < ltex->numLayers,
|
|
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
|
|
}
|
|
|
|
// "The width and height of image are non-zero."
|
|
cctx.require(image->width > 0 && image->height > 0, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
|
|
|
|
// Check for renderability
|
|
FormatFlags flags = db.getFormatInfo(image->internalFormat, ANY_FORMAT);
|
|
// If the format does not have the proper renderability flag, the
|
|
// completeness check _must_ fail.
|
|
cctx.require((flags & formatFlag(attPoint)) != 0, GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
|
|
// If the format is only optionally renderable, the completeness check _can_ fail.
|
|
cctx.canRequire((flags & REQUIRED_RENDERABLE) != 0,
|
|
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
|
|
}
|
|
|
|
} // namespace config
|
|
|
|
using namespace config;
|
|
|
|
void Checker::require (bool condition, GLenum error)
|
|
{
|
|
if (!condition)
|
|
{
|
|
m_statusCodes.erase(GL_FRAMEBUFFER_COMPLETE);
|
|
m_statusCodes.insert(error);
|
|
}
|
|
}
|
|
|
|
void Checker::canRequire (bool condition, GLenum error)
|
|
{
|
|
if (!condition)
|
|
m_statusCodes.insert(error);
|
|
}
|
|
|
|
FboVerifier::FboVerifier (const FormatDB& formats, CheckerFactory& factory)
|
|
: m_formats (formats)
|
|
, m_factory (factory)
|
|
{
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Return acceptable framebuffer status codes.
|
|
*
|
|
* This function examines the framebuffer configuration descriptor `fboConfig`
|
|
* and returns the set of status codes that `glCheckFramebufferStatus` is
|
|
* allowed to return on a conforming implementation when given a framebuffer
|
|
* whose configuration adheres to `fboConfig`.
|
|
*
|
|
* The returned set is guaranteed to be non-empty, but it may contain multiple
|
|
* INCOMPLETE statuses (if there are multiple errors in the spec), or or a mix
|
|
* of COMPLETE and INCOMPLETE statuses (if supporting a FBO with this spec is
|
|
* optional). Furthermore, the statuses may contain GL error codes, which
|
|
* indicate that trying to create a framebuffer configuration like this could
|
|
* have failed with an error (if one was checked for) even before
|
|
* `glCheckFramebufferStatus` was ever called.
|
|
*
|
|
*//*--------------------------------------------------------------------*/
|
|
StatusCodes FboVerifier::validStatusCodes (const Framebuffer& fboConfig) const
|
|
{
|
|
const AttachmentMap& atts = fboConfig.attachments;
|
|
const UniquePtr<Checker> cctx(m_factory.createChecker());
|
|
|
|
for (TextureMap::const_iterator it = fboConfig.textures.begin();
|
|
it != fboConfig.textures.end(); it++)
|
|
{
|
|
const FormatFlags flags =
|
|
m_formats.getFormatInfo(it->second->internalFormat, ANY_FORMAT);
|
|
cctx->require((flags & TEXTURE_VALID) != 0, GL_INVALID_ENUM);
|
|
cctx->require((flags & TEXTURE_VALID) != 0, GL_INVALID_OPERATION);
|
|
cctx->require((flags & TEXTURE_VALID) != 0, GL_INVALID_VALUE);
|
|
}
|
|
|
|
for (RboMap::const_iterator it = fboConfig.rbos.begin(); it != fboConfig.rbos.end(); it++)
|
|
{
|
|
const FormatFlags flags =
|
|
m_formats.getFormatInfo(it->second->internalFormat, ANY_FORMAT);
|
|
cctx->require((flags & RENDERBUFFER_VALID) != 0, GL_INVALID_ENUM);
|
|
}
|
|
|
|
// "There is at least one image attached to the framebuffer."
|
|
// TODO: support XXX_framebuffer_no_attachments
|
|
cctx->require(!atts.empty(), GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
|
|
|
|
for (AttachmentMap::const_iterator it = atts.begin(); it != atts.end(); it++)
|
|
{
|
|
const GLenum attPoint = it->first;
|
|
const Attachment& att = *it->second;
|
|
const Image* const image = fboConfig.getImage(attachmentType(att), att.imageName);
|
|
checkAttachmentCompleteness(*cctx, att, attPoint, image, m_formats);
|
|
cctx->check(it->first, *it->second, image);
|
|
}
|
|
|
|
return cctx->getStatusCodes();
|
|
}
|
|
|
|
|
|
void Framebuffer::attach (glw::GLenum attPoint, const Attachment* att)
|
|
{
|
|
if (att == DE_NULL)
|
|
attachments.erase(attPoint);
|
|
else
|
|
attachments[attPoint] = att;
|
|
}
|
|
|
|
const Image* Framebuffer::getImage (GLenum type, glw::GLuint imgName) const
|
|
{
|
|
switch (type)
|
|
{
|
|
case GL_TEXTURE:
|
|
return lookupDefault(textures, imgName, DE_NULL);
|
|
case GL_RENDERBUFFER:
|
|
return lookupDefault(rbos, imgName, DE_NULL);
|
|
default:
|
|
DE_ASSERT(!"Bad image type");
|
|
}
|
|
return DE_NULL; // shut up compiler warning
|
|
}
|
|
|
|
void Framebuffer::setTexture (glw::GLuint texName, const Texture& texCfg)
|
|
{
|
|
textures[texName] = &texCfg;
|
|
}
|
|
|
|
void Framebuffer::setRbo (glw::GLuint rbName, const Renderbuffer& rbCfg)
|
|
{
|
|
rbos[rbName] = &rbCfg;
|
|
}
|
|
|
|
static void logField (TestLog& log, const string& field, const string& value)
|
|
{
|
|
log << TestLog::Message << field << ": " << value << TestLog::EndMessage;
|
|
}
|
|
|
|
static void logImage (const Image& img, TestLog& log, bool useType)
|
|
{
|
|
const GLenum type = img.internalFormat.unsizedType;
|
|
logField(log, "Internal format", getPixelFormatName(img.internalFormat.format));
|
|
if (useType && type != GL_NONE)
|
|
logField(log, "Format type", getTypeName(type));
|
|
logField(log, "Width", toString(img.width));
|
|
logField(log, "Height", toString(img.height));
|
|
}
|
|
|
|
static void logRenderbuffer (const Renderbuffer& rbo, TestLog& log)
|
|
{
|
|
logImage(rbo, log, false);
|
|
logField(log, "Samples", toString(rbo.numSamples));
|
|
}
|
|
|
|
static void logTexture (const Texture& tex, TestLog& log)
|
|
{
|
|
logField(log, "Type", glu::getTextureTargetName(glTarget(tex)));
|
|
logImage(tex, log, true);
|
|
logField(log, "Levels", toString(tex.numLevels));
|
|
if (const TextureLayered* const lTex = dynamic_cast<const TextureLayered*>(&tex))
|
|
logField(log, "Layers", toString(lTex->numLayers));
|
|
}
|
|
|
|
static void logAttachment (const Attachment& att, TestLog& log)
|
|
{
|
|
logField(log, "Target", getFramebufferTargetName(att.target));
|
|
logField(log, "Type", getFramebufferAttachmentTypeName(attachmentType(att)));
|
|
logField(log, "Image Name", toString(att.imageName));
|
|
if (const RenderbufferAttachment* const rAtt
|
|
= dynamic_cast<const RenderbufferAttachment*>(&att))
|
|
{
|
|
DE_UNREF(rAtt); // To shut up compiler during optimized builds.
|
|
DE_ASSERT(rAtt->renderbufferTarget == GL_RENDERBUFFER);
|
|
logField(log, "Renderbuffer Target", "GL_RENDERBUFFER");
|
|
}
|
|
else if (const TextureAttachment* const tAtt = dynamic_cast<const TextureAttachment*>(&att))
|
|
{
|
|
logField(log, "Mipmap Level", toString(tAtt->level));
|
|
if (const TextureFlatAttachment* const fAtt =
|
|
dynamic_cast<const TextureFlatAttachment*>(tAtt))
|
|
logField(log, "Texture Target", getTextureTargetName(fAtt->texTarget));
|
|
else if (const TextureLayerAttachment* const lAtt =
|
|
dynamic_cast<const TextureLayerAttachment*>(tAtt))
|
|
logField(log, "Layer", toString(lAtt->level));
|
|
}
|
|
}
|
|
|
|
void logFramebufferConfig (const Framebuffer& cfg, TestLog& log)
|
|
{
|
|
log << TestLog::Section("Framebuffer", "Framebuffer configuration");
|
|
|
|
const string rboDesc = cfg.rbos.empty()
|
|
? "No renderbuffers were created"
|
|
: "Renderbuffers created";
|
|
log << TestLog::Section("Renderbuffers", rboDesc);
|
|
for (RboMap::const_iterator it = cfg.rbos.begin(); it != cfg.rbos.end(); ++it)
|
|
{
|
|
const string num = toString(it->first);
|
|
log << TestLog::Section(num, "Renderbuffer " + num);
|
|
logRenderbuffer(*it->second, log);
|
|
log << TestLog::EndSection;
|
|
}
|
|
log << TestLog::EndSection; // Renderbuffers
|
|
|
|
const string texDesc = cfg.textures.empty()
|
|
? "No textures were created"
|
|
: "Textures created";
|
|
log << TestLog::Section("Textures", texDesc);
|
|
for (TextureMap::const_iterator it = cfg.textures.begin();
|
|
it != cfg.textures.end(); ++it)
|
|
{
|
|
const string num = toString(it->first);
|
|
log << TestLog::Section(num, "Texture " + num);
|
|
logTexture(*it->second, log);
|
|
log << TestLog::EndSection;
|
|
}
|
|
log << TestLog::EndSection; // Textures
|
|
|
|
const string attDesc = cfg.attachments.empty()
|
|
? "Framebuffer has no attachments"
|
|
: "Framebuffer attachments";
|
|
log << TestLog::Section("Attachments", attDesc);
|
|
for (AttachmentMap::const_iterator it = cfg.attachments.begin();
|
|
it != cfg.attachments.end(); it++)
|
|
{
|
|
const string attPointName = getFramebufferAttachmentName(it->first);
|
|
log << TestLog::Section(attPointName, "Attachment point " + attPointName);
|
|
logAttachment(*it->second, log);
|
|
log << TestLog::EndSection;
|
|
}
|
|
log << TestLog::EndSection; // Attachments
|
|
|
|
log << TestLog::EndSection; // Framebuffer
|
|
}
|
|
|
|
FboBuilder::FboBuilder (GLuint fbo, GLenum target, const glw::Functions& gl)
|
|
: m_error (GL_NO_ERROR)
|
|
, m_target (target)
|
|
, m_gl (gl)
|
|
{
|
|
m_gl.bindFramebuffer(m_target, fbo);
|
|
}
|
|
|
|
FboBuilder::~FboBuilder (void)
|
|
{
|
|
for (TextureMap::const_iterator it = textures.begin(); it != textures.end(); it++)
|
|
{
|
|
glDelete(*it->second, it->first, m_gl);
|
|
}
|
|
for (RboMap::const_iterator it = rbos.begin(); it != rbos.end(); it++)
|
|
{
|
|
glDelete(*it->second, it->first, m_gl);
|
|
}
|
|
m_gl.bindFramebuffer(m_target, 0);
|
|
for (Configs::const_iterator it = m_configs.begin(); it != m_configs.end(); it++)
|
|
{
|
|
delete *it;
|
|
}
|
|
}
|
|
|
|
void FboBuilder::checkError (void)
|
|
{
|
|
const GLenum error = m_gl.getError();
|
|
if (error != GL_NO_ERROR && m_error == GL_NO_ERROR)
|
|
m_error = error;
|
|
}
|
|
|
|
void FboBuilder::glAttach (GLenum attPoint, const Attachment* att)
|
|
{
|
|
if (att == NULL)
|
|
m_gl.framebufferRenderbuffer(m_target, attPoint, GL_RENDERBUFFER, 0);
|
|
else
|
|
attachAttachment(*att, attPoint, m_gl);
|
|
checkError();
|
|
attach(attPoint, att);
|
|
}
|
|
|
|
GLuint FboBuilder::glCreateTexture (const Texture& texCfg)
|
|
{
|
|
const GLuint texName = glCreate(texCfg, m_gl);
|
|
checkError();
|
|
setTexture(texName, texCfg);
|
|
return texName;
|
|
}
|
|
|
|
GLuint FboBuilder::glCreateRbo (const Renderbuffer& rbCfg)
|
|
{
|
|
const GLuint rbName = glCreate(rbCfg, m_gl);
|
|
checkError();
|
|
setRbo(rbName, rbCfg);
|
|
return rbName;
|
|
}
|
|
|
|
TransferFormat transferImageFormat (const ImageFormat& imgFormat)
|
|
{
|
|
if (imgFormat.unsizedType == GL_NONE)
|
|
return getTransferFormat(mapGLInternalFormat(imgFormat.format));
|
|
else
|
|
return TransferFormat(imgFormat.format, imgFormat.unsizedType);
|
|
}
|
|
|
|
} // FboUtil
|
|
} // gls
|
|
} // deqp
|