blob: 00887a868b9df98ab0902d03014e908d6144241f [file] [log] [blame]
#ifndef _GLSFBOUTIL_HPP
#define _GLSFBOUTIL_HPP
/*-------------------------------------------------------------------------
* 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 "gluRenderContext.hpp"
#include "gluContextInfo.hpp"
#include "glwDefs.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "gluTextureUtil.hpp"
#include "tcuTestLog.hpp"
#include "tcuDefs.hpp"
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include <iterator>
namespace deqp
{
namespace gls
{
// Utilities for standard containers. \todo [2013-12-10 lauri] Move to decpp?
//! A pair of iterators to present a range.
//! \note This must be POD to allow static initialization.
//! \todo [2013-12-03 lauri] Move this to decpp?
template <typename T>
struct Range
{
typedef const T* const_iterator;
const T* m_begin;
const T* m_end;
const T* begin (void) const { return m_begin; }
const T* end (void) const { return m_end; }
};
#define GLS_ARRAY_RANGE(ARR) { DE_ARRAY_BEGIN(ARR), DE_ARRAY_END(ARR) }
#define GLS_NULL_RANGE { DE_NULL, DE_NULL }
//! A pair type that, unlike stl::pair, is POD so it can be statically initialized.
template <typename T1, typename T2>
struct Pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
};
template<typename C>
C intersection(const C& s1, const C& s2)
{
C ret;
std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(),
std::insert_iterator<C>(ret, ret.begin()));
return ret;
}
// \todo [2013-12-03 lauri] move to decpp?
template<typename C>
inline bool isMember (const typename C::key_type& key, const C& container)
{
typename C::const_iterator it = container.find(key);
return (it != container.end());
}
template <typename M> inline
const typename M::mapped_type* lookupMaybe (const M& map,
const typename M::key_type& key)
{
typename M::const_iterator it = map.find(key);
if (it == map.end())
return DE_NULL;
return &it->second;
}
template<typename M> inline
const typename M::mapped_type& lookupDefault (const M& map,
const typename M::key_type& key,
const typename M::mapped_type& fallback)
{
const typename M::mapped_type* ptr = lookupMaybe(map, key);
return ptr == DE_NULL ? fallback : *ptr;
}
template<typename M>
const typename M::mapped_type& lookup (const M& map,
const typename M::key_type& key)
{
const typename M::mapped_type* ptr = lookupMaybe(map, key);
if (ptr == DE_NULL)
throw std::out_of_range("key not found in map");
return *ptr;
}
template<typename C>
inline bool contains (const C& container, const typename C::value_type& item)
{
const typename C::const_iterator it = container.find(item);
return (it != container.end());
}
template<typename M> static inline
bool insert(const typename M::key_type& key, const typename M::mapped_type& value, M& map)
{
typename M::value_type entry(key, value);
std::pair<typename M::iterator,bool> ret = map.insert(entry);
return ret.second;
}
std::vector<std::string> splitString(const std::string& s);
namespace FboUtil
{
//! Configurations for framebuffer objects and their attachments.
class FboVerifier;
class FboBuilder;
typedef deUint32 FormatKey;
#define GLS_UNSIZED_FORMATKEY(FORMAT, TYPE) \
(deUint32(TYPE) << 16 | deUint32(FORMAT))
typedef Range<FormatKey> FormatKeys;
struct ImageFormat
{
glw::GLenum format;
//! Type if format is unsized, GL_NONE if sized.
glw::GLenum unsizedType;
bool operator< (const ImageFormat& other) const
{
return (format < other.format ||
(format == other.format && unsizedType < other.unsizedType));
}
static ImageFormat none (void)
{
ImageFormat fmt = { GL_NONE, GL_NONE };
return fmt;
}
};
static inline ImageFormat formatKeyInfo(FormatKey key)
{
ImageFormat fmt = { key & 0xffff, key >> 16 };
return fmt;
}
enum FormatFlags
{
ANY_FORMAT = 0,
COLOR_RENDERABLE = 1 << 0,
DEPTH_RENDERABLE = 1 << 1,
STENCIL_RENDERABLE = 1 << 2,
RENDERBUFFER_VALID = 1 << 3,
TEXTURE_VALID = 1 << 4,
REQUIRED_RENDERABLE = 1 << 5, //< Without this, renderability is allowed, not required.
};
static inline FormatFlags operator|(FormatFlags f1, FormatFlags f2)
{
return FormatFlags(deUint32(f1) | deUint32(f2));
}
FormatFlags formatFlag(glw::GLenum context);
typedef std::set<ImageFormat> Formats;
class FormatDB
{
public:
void addFormat (ImageFormat format, FormatFlags flags);
Formats getFormats (FormatFlags requirements) const;
FormatFlags getFormatInfo (ImageFormat format,
FormatFlags fallback) const;
private:
typedef std::map<ImageFormat, FormatFlags> FormatMap;
FormatMap m_map;
};
typedef Pair<FormatFlags, FormatKeys> FormatEntry;
typedef Range<FormatEntry> FormatEntries;
// \todo [2013-12-20 lauri] It turns out that format properties in extensions
// are actually far too fine-grained for this bundling to be reasonable,
// especially given the syntactic cumbersomeness of static arrays. It's better
// to list each entry separately.
struct FormatExtEntry
{
const char* extensions;
deUint32 flags;
Range<FormatKey> formats;
};
typedef Range<FormatExtEntry> FormatExtEntries;
void addFormats (FormatDB& db, FormatEntries stdFmts);
void addExtFormats (FormatDB& db, FormatExtEntries extFmts,
const glu::RenderContext* ctx);
glu::TransferFormat transferImageFormat (const ImageFormat& imgFormat);
namespace config
{
struct Config
{
virtual ~Config (void) {};
};
struct Image : public Config
{
ImageFormat internalFormat;
glw::GLsizei width;
glw::GLsizei height;
protected:
Image (void)
: internalFormat (ImageFormat::none())
, width (0)
, height (0) {}
};
struct Renderbuffer : public Image
{
Renderbuffer (void) : numSamples(0) {}
glw::GLsizei numSamples;
};
struct Texture : public Image
{
Texture (void) : numLevels(1) {}
glw::GLint numLevels;
};
struct TextureFlat : public Texture
{
};
struct Texture2D : public TextureFlat
{
};
struct TextureCubeMap : public TextureFlat
{
};
struct TextureLayered : public Texture
{
TextureLayered (void) : numLayers(1) {}
glw::GLsizei numLayers;
};
struct Texture3D : public TextureLayered
{
};
struct Texture2DArray : public TextureLayered
{
};
struct Attachment : public Config
{
Attachment (void) : target(GL_FRAMEBUFFER), imageName(0) {}
glw::GLenum target;
glw::GLuint imageName;
//! Returns `true` iff this attachment is "framebuffer attachment
//! complete" when bound to attachment point `attPoint`, and the current
//! image with name `imageName` is `image`, using `vfr` to check format
//! renderability.
bool isComplete (glw::GLenum attPoint, const Image* image,
const FboVerifier& vfr) const;
};
struct RenderbufferAttachment : public Attachment
{
RenderbufferAttachment (void)
: renderbufferTarget(GL_RENDERBUFFER) {}
glw::GLenum renderbufferTarget;
};
struct TextureAttachment : public Attachment
{
TextureAttachment (void) : level(0) {}
glw::GLint level;
};
struct TextureFlatAttachment : public TextureAttachment
{
TextureFlatAttachment (void) : texTarget(GL_NONE) {}
glw::GLenum texTarget;
};
struct TextureLayerAttachment : public TextureAttachment
{
TextureLayerAttachment (void) : layer(0) {}
glw::GLsizei layer;
};
glw::GLenum attachmentType (const Attachment& att);
glw::GLsizei imageNumSamples (const Image& img);
//! Mapping from attachment points to attachment configurations.
typedef std::map<glw::GLenum, const Attachment*> AttachmentMap;
//! Mapping from object names to texture configurations.
typedef std::map<glw::GLuint, const Texture*> TextureMap;
//! Mapping from object names to renderbuffer configurations.
typedef std::map<glw::GLuint, const Renderbuffer*> RboMap;
//! A framebuffer configuration.
struct Framebuffer
{
AttachmentMap attachments;
TextureMap textures;
RboMap rbos;
void attach (glw::GLenum attPoint, const Attachment* att);
void setTexture (glw::GLuint texName, const Texture& texCfg);
void setRbo (glw::GLuint rbName, const Renderbuffer& rbCfg);
const Image* getImage (glw::GLenum type, glw::GLuint imgName) const;
};
} // config
void logFramebufferConfig(const config::Framebuffer& cfg, tcu::TestLog& log);
class FboBuilder : public config::Framebuffer
{
public:
void glAttach (glw::GLenum attPoint,
const config::Attachment* att);
glw::GLuint glCreateTexture (const config::Texture& texCfg);
glw::GLuint glCreateRbo (const config::Renderbuffer& rbCfg);
FboBuilder (glw::GLuint fbo, glw::GLenum target,
const glw::Functions& gl);
~FboBuilder (void);
glw::GLenum getError (void) { return m_error; }
//! Allocate a new configuration of type `Config` (which must be a
//! subclass of `config::Config`), and return a referenc to it. The newly
//! allocated object will be freed when this builder object is destroyed.
template<typename Config>
Config& makeConfig (void)
{
Config* cfg = new Config();
m_configs.insert(cfg);
return *cfg;
}
private:
typedef std::set<config::Config*> Configs;
void checkError (void);
glw::GLenum m_error; //< The first GL error encountered.
glw::GLenum m_target;
const glw::Functions& m_gl;
Configs m_configs;
};
typedef std::set<glw::GLenum> StatusCodes;
class Checker
{
public:
Checker (void) { m_statusCodes.insert(GL_FRAMEBUFFER_COMPLETE); }
virtual ~Checker (void) {}
void require (bool condition, glw::GLenum error);
void canRequire (bool condition, glw::GLenum error);
StatusCodes getStatusCodes (void) { return m_statusCodes; }
virtual void check (glw::GLenum attPoint, const config::Attachment& att,
const config::Image* image) = 0;
private:
StatusCodes m_statusCodes; //< Allowed return values for glCheckFramebufferStatus.
};
class CheckerFactory
{
public:
virtual Checker* createChecker (void) = 0;
};
typedef std::set<glw::GLenum> AttachmentPoints;
typedef std::set<ImageFormat> Formats;
class FboVerifier
{
public:
FboVerifier (const FormatDB& formats,
CheckerFactory& factory);
StatusCodes validStatusCodes (const config::Framebuffer& cfg) const;
private:
const FormatDB& m_formats;
CheckerFactory& m_factory;
};
} // FboUtil
} // gls
} // deqp
#endif // _GLSFBOUTIL_HPP