Commit a4903b70 by Geoff Lang

Support multisampled framebuffers with the GL backend.

Move validation of sample counts into the Renderbuffer implementations because the exact supported sample counts are not always known. BUG=angleoproject:886 Change-Id: I9c90d9d435e940b852343a29a6aa11d6cb1ad23b Reviewed-on: https://chromium-review.googlesource.com/255513Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Tested-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 02bce6e5
......@@ -33,6 +33,7 @@ struct TextureCaps
// Support for being used as a framebuffer attachment or renderbuffer format
bool renderable;
// Set of supported sample counts, only guaranteed to be valid in ES3.
SupportedSampleSet sampleCounts;
// Get the maximum number of samples supported
......
......@@ -1548,7 +1548,6 @@ void Context::initCaps(GLuint clientVersion)
mCaps.maxFragmentInputComponents = std::min<GLuint>(mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
GLuint maxSamples = 0;
mCaps.compressedTextureFormats.clear();
const TextureCapsMap &rendererFormats = mRenderer->getRendererTextureCaps();
......@@ -1569,7 +1568,6 @@ void Context::initCaps(GLuint clientVersion)
{
formatCaps.sampleCounts.clear();
}
maxSamples = std::max(maxSamples, formatCaps.getMaxSamples());
if (formatCaps.texturable && formatInfo.compressed)
{
......@@ -1578,8 +1576,6 @@ void Context::initCaps(GLuint clientVersion)
mTextureCaps.insert(format, formatCaps);
}
mCaps.maxSamples = maxSamples;
}
Data Context::getData() const
......
......@@ -41,6 +41,17 @@ gl::Error RenderbufferD3D::setStorageMultisample(size_t samples, GLenum internal
creationFormat = GL_DEPTH24_STENCIL8_OES;
}
// ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
// the specified storage.
// Because ES 3.0 already knows the exact number of supported samples, it would already have been
// validated and generated GL_INVALID_VALUE.
const gl::TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(creationFormat);
if (samples > formatCaps.getMaxSamples())
{
return gl::Error(GL_OUT_OF_MEMORY, "Renderbuffer format does not support %u samples, %u is the maximum.",
samples, formatCaps.getMaxSamples());
}
RenderTargetD3D *newRT = NULL;
gl::Error error = mRenderer->createRenderTarget(width, height, creationFormat, samples, &newRT);
if (error.isError())
......
......@@ -7,18 +7,89 @@
// FunctionsGL.cpp: Implements the FuntionsGL class to contain loaded GL functions
#include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/renderergl_utils.h"
namespace rx
{
static void GetGLVersion(PFNGLGETSTRINGPROC getStringFunction, GLuint *outMajorVersion, GLuint *outMinorVersion,
bool *outIsES)
{
const std::string version = reinterpret_cast<const char*>(getStringFunction(GL_VERSION));
if (version.find("OpenGL ES") == std::string::npos)
{
// ES spec states that the GL_VERSION string will be in the following format:
// "OpenGL ES N.M vendor-specific information"
*outIsES = false;
*outMajorVersion = version[0] - '0';
*outMinorVersion = version[2] - '0';
}
else
{
// OpenGL spec states the GL_VERSION string will be in the following format:
// <version number><space><vendor-specific information>
// The version number is either of the form major number.minor number or major
// number.minor number.release number, where the numbers all have one or more
// digits
*outIsES = true;
*outMajorVersion = version[10] - '0';
*outMinorVersion = version[12] - '0';
}
}
static std::vector<std::string> GetNonIndexedExtensions(PFNGLGETSTRINGPROC getStringFunction)
{
std::vector<std::string> result;
std::istringstream stream(reinterpret_cast<const char*>(getStringFunction(GL_EXTENSIONS)));
std::string extension;
while (std::getline(stream, extension, ' '))
{
result.push_back(extension);
}
return result;
}
static std::vector<std::string> GetIndexedExtensions(PFNGLGETINTEGERVPROC getIntegerFunction, PFNGLGETSTRINGIPROC getStringIFunction)
{
std::vector<std::string> result;
GLint numExtensions;
getIntegerFunction(GL_NUM_EXTENSIONS, &numExtensions);
result.reserve(numExtensions);
for (GLint i = 0; i < numExtensions; i++)
{
result.push_back(reinterpret_cast<const char*>(getStringIFunction(GL_EXTENSIONS, i)));
}
return result;
}
template <typename T>
static void AssignGLEntryPoint(void *function, T *outFunction)
{
*outFunction = reinterpret_cast<T>(function);
}
template <typename T>
static void AssignGLExtensionEntryPoint(const std::vector<std::string> &extensions, const std::string &extension, void *function, T *outFunction)
{
if (std::find(extensions.begin(), extensions.end(), extension) != extensions.end())
{
*outFunction = reinterpret_cast<T>(function);
}
}
FunctionsGL::FunctionsGL()
: blendFunc(nullptr),
: majorVersion(0),
minorVersion(0),
openGLES(false),
extensions(),
blendFunc(nullptr),
clear(nullptr),
clearColor(nullptr),
clearDepth(nullptr),
......@@ -694,8 +765,24 @@ FunctionsGL::~FunctionsGL()
{
}
void FunctionsGL::initialize(GLuint majorVersion, GLuint minorVersion)
void FunctionsGL::initialize()
{
// Grab the version number
AssignGLEntryPoint(loadProcAddress("glGetString"), &getString);
GetGLVersion(getString, &majorVersion, &minorVersion, &openGLES);
// Grab the GL extensions
if (majorVersion > 3 || majorVersion == 3 && minorVersion >= 0)
{
AssignGLEntryPoint(loadProcAddress("glGetIntegerv"), &getIntegerv);
AssignGLEntryPoint(loadProcAddress("glGetStringi"), &getStringi);
extensions = GetIndexedExtensions(getIntegerv, getStringi);
}
else
{
extensions = GetNonIndexedExtensions(getString);
}
// 1.0
if (majorVersion > 1 || majorVersion == 1 && minorVersion >= 0)
{
......@@ -1024,6 +1111,9 @@ void FunctionsGL::initialize(GLuint majorVersion, GLuint minorVersion)
AssignGLEntryPoint(loadProcAddress("glVertexAttribI4uiv"), &vertexAttribI4uiv);
AssignGLEntryPoint(loadProcAddress("glVertexAttribI4usv"), &vertexAttribI4usv);
AssignGLEntryPoint(loadProcAddress("glVertexAttribIPointer"), &vertexAttribIPointer);
// Extensions
AssignGLExtensionEntryPoint(extensions, "GL_ARB_internalformat_query", loadProcAddress("glGetInternalformativ"), &getInternalformativ);
}
// 3.1
......
......@@ -22,8 +22,17 @@ class FunctionsGL
FunctionsGL();
virtual ~FunctionsGL();
void initialize(GLuint majorVersion, GLuint minorVersion);
void initialize();
// Version information
GLuint majorVersion;
GLuint minorVersion;
bool openGLES;
// Extensions
std::vector<std::string> extensions;
// Entry Points
// 1.0
PFNGLBLENDFUNCPROC blendFunc;
PFNGLCLEARPROC clear;
......
......@@ -9,17 +9,20 @@
#include "libANGLE/renderer/gl/RenderbufferGL.h"
#include "common/debug.h"
#include "libANGLE/Caps.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h"
#include "libANGLE/renderer/gl/renderergl_utils.h"
namespace rx
{
RenderbufferGL::RenderbufferGL(const FunctionsGL *functions, StateManagerGL *stateManager)
RenderbufferGL::RenderbufferGL(const FunctionsGL *functions, StateManagerGL *stateManager, const gl::TextureCapsMap &textureCaps)
: RenderbufferImpl(),
mFunctions(functions),
mStateManager(stateManager),
mTextureCaps(textureCaps),
mRenderbufferID(0)
{
mFunctions->genRenderbuffers(1, &mRenderbufferID);
......@@ -45,6 +48,25 @@ gl::Error RenderbufferGL::setStorageMultisample(size_t samples, GLenum internalf
{
mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mRenderbufferID);
mFunctions->renderbufferStorageMultisample(GL_RENDERBUFFER, samples, internalformat, width, height);
const gl::TextureCaps &formatCaps = mTextureCaps.get(internalformat);
if (samples > formatCaps.getMaxSamples())
{
// Before version 4.2, it is unknown if the specific internal format can support the requested number
// of samples. It is expected that GL_OUT_OF_MEMORY is returned if the renderbuffer cannot be created.
GLenum error = GL_NO_ERROR;
do
{
GLenum error = mFunctions->getError();
if (error == GL_OUT_OF_MEMORY)
{
return gl::Error(GL_OUT_OF_MEMORY);
}
ASSERT(error == GL_NO_ERROR);
} while (error != GL_NO_ERROR);
}
return gl::Error(GL_NO_ERROR);
}
......
......@@ -11,6 +11,11 @@
#include "libANGLE/renderer/RenderbufferImpl.h"
namespace gl
{
class TextureCapsMap;
}
namespace rx
{
......@@ -20,7 +25,7 @@ class StateManagerGL;
class RenderbufferGL : public RenderbufferImpl
{
public:
RenderbufferGL(const FunctionsGL *functions, StateManagerGL *stateManager);
RenderbufferGL(const FunctionsGL *functions, StateManagerGL *stateManager, const gl::TextureCapsMap &textureCaps);
~RenderbufferGL() override;
virtual gl::Error setStorage(GLenum internalformat, size_t width, size_t height) override;
......@@ -31,6 +36,7 @@ class RenderbufferGL : public RenderbufferImpl
private:
const FunctionsGL *mFunctions;
StateManagerGL *mStateManager;
const gl::TextureCapsMap &mTextureCaps;
GLuint mRenderbufferID;
};
......
......@@ -124,7 +124,7 @@ TextureImpl *RendererGL::createTexture(GLenum target)
RenderbufferImpl *RendererGL::createRenderbuffer()
{
return new RenderbufferGL(mFunctions, mStateManager);
return new RenderbufferGL(mFunctions, mStateManager, getRendererTextureCaps());
}
BufferImpl *RendererGL::createBuffer()
......@@ -196,18 +196,13 @@ std::string RendererGL::getRendererDescription() const
std::string nativeVendorString(reinterpret_cast<const char*>(mFunctions->getString(GL_VENDOR)));
std::string nativeRendererString(reinterpret_cast<const char*>(mFunctions->getString(GL_RENDERER)));
GLuint major;
GLuint minor;
bool isES;
nativegl::GetGLVersion(mFunctions->getString, &major, &minor, &isES);
std::ostringstream rendererString;
rendererString << nativeVendorString << " " << nativeRendererString << " OpenGL";
if (isES)
if (mFunctions->openGLES)
{
rendererString << " ES";
}
rendererString << " " << major << "." << minor;
rendererString << " " << mFunctions->majorVersion << "." << mFunctions->minorVersion;
return rendererString.str();
}
......
......@@ -21,62 +21,35 @@
namespace rx
{
namespace nativegl
{
void GetGLVersion(PFNGLGETSTRINGPROC getStringFunction, GLuint *outMajorVersion, GLuint *outMinorVersion,
bool *outIsES)
{
const std::string version = reinterpret_cast<const char*>(getStringFunction(GL_VERSION));
if (version.find("OpenGL ES") == std::string::npos)
{
// ES spec states that the GL_VERSION string will be in the following format:
// "OpenGL ES N.M vendor-specific information"
*outIsES = false;
*outMajorVersion = version[0] - '0';
*outMinorVersion = version[2] - '0';
}
else
{
// OpenGL spec states the GL_VERSION string will be in the following format:
// <version number><space><vendor-specific information>
// The version number is either of the form major number.minor number or major
// number.minor number.release number, where the numbers all have one or more
// digits
*outIsES = true;
*outMajorVersion = version[10] - '0';
*outMinorVersion = version[12] - '0';
}
}
std::vector<std::string> GetGLExtensions(PFNGLGETSTRINGPROC getStringFunction)
{
std::vector<std::string> result;
std::istringstream stream(reinterpret_cast<const char*>(getStringFunction(GL_EXTENSIONS)));
std::string extension;
while (std::getline(stream, extension, ' '))
{
result.push_back(extension);
}
return result;
}
}
namespace nativegl_gl
{
static gl::TextureCaps GenerateTextureFormatCaps(const FunctionsGL *functions, GLenum internalFormat, GLuint majorVersion, GLuint minorVersion,
const std::vector<std::string> &extensions)
static gl::TextureCaps GenerateTextureFormatCaps(const FunctionsGL *functions, GLenum internalFormat)
{
gl::TextureCaps textureCaps;
const nativegl::InternalFormat &formatInfo = nativegl::GetInternalFormatInfo(internalFormat);
textureCaps.texturable = formatInfo.textureSupport(majorVersion, minorVersion, extensions);
textureCaps.renderable = formatInfo.renderSupport(majorVersion, minorVersion, extensions);
textureCaps.filterable = formatInfo.filterSupport(majorVersion, minorVersion, extensions);
textureCaps.texturable = formatInfo.textureSupport(functions->majorVersion, functions->minorVersion, functions->extensions);
textureCaps.renderable = formatInfo.renderSupport(functions->majorVersion, functions->minorVersion, functions->extensions);
textureCaps.filterable = formatInfo.filterSupport(functions->majorVersion, functions->minorVersion, functions->extensions);
// glGetInternalformativ is not available until version 4.2 but may be available through the 3.0
// extension GL_ARB_internalformat_query
if (textureCaps.renderable && functions->getInternalformativ)
{
GLint numSamples = 0;
functions->getInternalformativ(GL_RENDERBUFFER, internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &numSamples);
if (numSamples > 0)
{
std::vector<GLint> samples(numSamples);
functions->getInternalformativ(GL_RENDERBUFFER, internalFormat, GL_SAMPLES, samples.size(), &samples[0]);
for (size_t sampleIndex = 0; sampleIndex < samples.size(); sampleIndex++)
{
textureCaps.sampleCounts.insert(samples[sampleIndex]);
}
}
}
return textureCaps;
}
......@@ -91,23 +64,13 @@ static GLint QuerySingleGLInt(const FunctionsGL *functions, GLenum name)
void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap,
gl::Extensions *extensions)
{
GLuint majorVersion = 0;
GLuint minorVersion = 0;
bool isES = false;
nativegl::GetGLVersion(functions->getString, &majorVersion, &minorVersion, &isES);
std::vector<std::string> nativeExtensions = nativegl::GetGLExtensions(functions->getString);
// Texture format support checks
GLuint maxSamples = 0;
const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats();
for (GLenum internalFormat : allFormats)
{
gl::TextureCaps textureCaps = GenerateTextureFormatCaps(functions, internalFormat, majorVersion, minorVersion, nativeExtensions);
gl::TextureCaps textureCaps = GenerateTextureFormatCaps(functions, internalFormat);
textureCapsMap->insert(internalFormat, textureCaps);
maxSamples = std::max(maxSamples, textureCaps.getMaxSamples());
if (gl::GetInternalFormatInfo(internalFormat).compressed)
{
caps->compressedTextureFormats.push_back(internalFormat);
......@@ -184,13 +147,14 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM
caps->maxTransformFeedbackSeparateComponents = 4;
// Table 6.35, Framebuffer Dependent Values
caps->maxSamples = 4;
caps->maxSamples = QuerySingleGLInt(functions, GL_MAX_SAMPLES);
// Extension support
extensions->setTextureExtensionSupport(*textureCapsMap);
extensions->textureNPOT = true;
extensions->textureStorage = true;
extensions->fboRenderMipmap = true;
extensions->framebufferMultisample = caps->maxSamples > 0;
}
}
......
......@@ -25,14 +25,6 @@ namespace rx
{
class FunctionsGL;
namespace nativegl
{
void GetGLVersion(PFNGLGETSTRINGPROC getStringFunction, GLuint *outMajorVersion, GLuint *outMinorVersion, bool *outIsES);
std::vector<std::string> GetGLExtensions(PFNGLGETSTRINGPROC getStringFunction);
}
namespace nativegl_gl
{
......
......@@ -58,8 +58,6 @@ class FunctionsGLWindows : public FunctionsGL
DisplayWGL::DisplayWGL()
: DisplayGL(),
mOpenGLModule(nullptr),
mGLVersionMajor(0),
mGLVersionMinor(0),
mFunctionsWGL(nullptr),
mFunctionsGL(nullptr),
mWindowClass(0),
......@@ -186,12 +184,6 @@ egl::Error DisplayWGL::initialize(egl::Display *display)
return egl::Error(EGL_NOT_INITIALIZED, "Failed to get glGetString pointer.");
}
GLuint maxGLVersionMajor = 0;
GLuint maxGLVersionMinor = 0;
bool isES = false;
nativegl::GetGLVersion(getString, &maxGLVersionMajor, &maxGLVersionMinor, &isES);
ASSERT(!isES);
// Reinitialize the wgl functions to grab the extensions
mFunctionsWGL->intialize(mOpenGLModule, dummyDeviceContext);
......@@ -283,9 +275,6 @@ egl::Error DisplayWGL::initialize(egl::Display *display)
if (!mWGLContext)
{
// Don't have control over GL versions
mGLVersionMajor = maxGLVersionMajor;
mGLVersionMinor = maxGLVersionMinor;
mWGLContext = mFunctionsWGL->createContext(mDeviceContext);
}
......@@ -299,11 +288,8 @@ egl::Error DisplayWGL::initialize(egl::Display *display)
return egl::Error(EGL_NOT_INITIALIZED, "Failed to make the intermediate WGL context current.");
}
nativegl::GetGLVersion(getString, &mGLVersionMajor, &mGLVersionMinor, &isES);
ASSERT(!isES);
mFunctionsGL = new FunctionsGLWindows(mOpenGLModule, mFunctionsWGL->getProcAddress);
mFunctionsGL->initialize(mGLVersionMajor, mGLVersionMinor);
mFunctionsGL->initialize();
return DisplayGL::initialize(display);
}
......
......@@ -55,8 +55,6 @@ class DisplayWGL : public DisplayGL
void generateCaps(egl::Caps *outCaps) const override;
HMODULE mOpenGLModule;
GLuint mGLVersionMajor;
GLuint mGLVersionMinor;
FunctionsWGL *mFunctionsWGL;
FunctionsGL *mFunctionsGL;
......
......@@ -362,11 +362,15 @@ bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum tar
// ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
// the specified storage. This is different than ES 3.0 in which a sample number higher
// than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
// The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
if (context->getClientVersion() >= 3)
{
context->recordError(Error(GL_OUT_OF_MEMORY));
return false;
const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
{
context->recordError(Error(GL_OUT_OF_MEMORY));
return false;
}
}
return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment