blob: afddcfb107f656fc11eaaa4286aeb52d715d7124 [file] [log] [blame]
//
// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// gl_raii:
// Helper methods for containing GL objects like buffers and textures.
#ifndef ANGLE_TESTS_GL_RAII_H_
#define ANGLE_TESTS_GL_RAII_H_
#include <functional>
#include "angle_gl.h"
namespace angle
{
// This is a bit of hack to work around a bug in MSVS intellisense, and make it very easy to
// use the correct function pointer type without worrying about the various definitions of
// GL_APICALL.
using GLGen = decltype(glGenBuffers);
using GLDelete = decltype(glDeleteBuffers);
template <GLGen GenF, GLDelete DeleteF>
class GLWrapper : angle::NonCopyable
{
public:
GLWrapper() {}
~GLWrapper() { DeleteF(1, &mHandle); }
// The move-constructor and move-assignment operators are necessary so that the data within a
// GLWrapper object can be relocated.
GLWrapper(GLWrapper &&rht) : mHandle(rht.mHandle) { rht.mHandle = 0u; }
GLWrapper &operator=(GLWrapper &&rht)
{
if (this != &rht)
{
std::swap(mHandle, rht.mHandle);
}
return *this;
}
void reset()
{
if (mHandle != 0u)
{
DeleteF(1, &mHandle);
mHandle = 0u;
}
}
GLuint get()
{
if (!mHandle)
{
GenF(1, &mHandle);
}
return mHandle;
}
operator GLuint() { return get(); }
private:
GLuint mHandle = 0u;
};
using GLVertexArray = GLWrapper<glGenVertexArrays, glDeleteVertexArrays>;
using GLBuffer = GLWrapper<glGenBuffers, glDeleteBuffers>;
using GLTexture = GLWrapper<glGenTextures, glDeleteTextures>;
using GLFramebuffer = GLWrapper<glGenFramebuffers, glDeleteFramebuffers>;
using GLRenderbuffer = GLWrapper<glGenRenderbuffers, glDeleteRenderbuffers>;
using GLSampler = GLWrapper<glGenSamplers, glDeleteSamplers>;
using GLTransformFeedback = GLWrapper<glGenTransformFeedbacks, glDeleteTransformFeedbacks>;
using GLProgramPipeline = GLWrapper<glGenProgramPipelines, glDeleteProgramPipelines>;
using GLQueryEXT = GLWrapper<glGenQueriesEXT, glDeleteQueriesEXT>;
class GLShader : angle::NonCopyable
{
public:
GLShader() = delete;
explicit GLShader(GLenum shaderType) { mHandle = glCreateShader(shaderType); }
~GLShader() { glDeleteShader(mHandle); }
GLuint get() { return mHandle; }
operator GLuint() { return get(); }
private:
GLuint mHandle;
};
// Don't use GLProgram directly, use ANGLE_GL_PROGRAM.
namespace priv
{
class GLProgram
{
public:
GLProgram() : mHandle(0) {}
~GLProgram() { glDeleteProgram(mHandle); }
void makeEmpty() { mHandle = glCreateProgram(); }
void makeCompute(const char *computeShader) { mHandle = CompileComputeProgram(computeShader); }
void makeRaster(const char *vertexShader, const char *fragmentShader)
{
mHandle = CompileProgram(vertexShader, fragmentShader);
}
void makeRaster(const char *vertexShader,
const char *geometryShader,
const char *fragmentShader)
{
mHandle = CompileProgramWithGS(vertexShader, geometryShader, fragmentShader);
}
void makeRasterWithTransformFeedback(const char *vertexShader,
const char *fragmentShader,
const std::vector<std::string> &tfVaryings,
GLenum bufferMode)
{
mHandle = CompileProgramWithTransformFeedback(vertexShader, fragmentShader, tfVaryings,
bufferMode);
}
void makeBinaryOES(const std::vector<uint8_t> &binary, GLenum binaryFormat)
{
mHandle = LoadBinaryProgramOES(binary, binaryFormat);
}
void makeBinaryES3(const std::vector<uint8_t> &binary, GLenum binaryFormat)
{
mHandle = LoadBinaryProgramES3(binary, binaryFormat);
}
bool valid() const { return mHandle != 0; }
GLuint get()
{
ASSERT(valid());
return mHandle;
}
operator GLuint() { return get(); }
private:
GLuint mHandle;
};
} // namespace priv
#define ANGLE_GL_EMPTY_PROGRAM(name) \
priv::GLProgram name; \
name.makeEmpty(); \
ASSERT_TRUE(name.valid());
#define ANGLE_GL_PROGRAM(name, vertex, fragment) \
priv::GLProgram name; \
name.makeRaster(vertex, fragment); \
ASSERT_TRUE(name.valid());
#define ANGLE_GL_PROGRAM_WITH_GS(name, vertex, geometry, fragment) \
priv::GLProgram name; \
name.makeRaster(vertex, geometry, fragment); \
ASSERT_TRUE(name.valid());
#define ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(name, vertex, fragment, tfVaryings, bufferMode) \
priv::GLProgram name; \
name.makeRasterWithTransformFeedback(vertex, fragment, tfVaryings, bufferMode); \
ASSERT_TRUE(name.valid());
#define ANGLE_GL_COMPUTE_PROGRAM(name, compute) \
priv::GLProgram name; \
name.makeCompute(compute); \
ASSERT_TRUE(name.valid());
#define ANGLE_GL_BINARY_OES_PROGRAM(name, binary, binaryFormat) \
priv::GLProgram name; \
name.makeBinaryOES(binary, binaryFormat); \
ASSERT_TRUE(name.valid());
#define ANGLE_GL_BINARY_ES3_PROGRAM(name, binary, binaryFormat) \
priv::GLProgram name; \
name.makeBinaryES3(binary, binaryFormat); \
ASSERT_TRUE(name.valid());
} // namespace angle
#endif // ANGLE_TESTS_GL_RAII_H_