blob: 1ee1cf1d8ad46911620c488e41781aabb059da2d [file] [log] [blame]
//
// Copyright 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 "util/shader_utils.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);
class GLWrapper : angle::NonCopyable
{
public:
GLWrapper(GLGen *genFunc, GLDelete *deleteFunc) : mGenFunc(genFunc), mDeleteFunc(deleteFunc) {}
~GLWrapper() { (*mDeleteFunc)(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)
: mGenFunc(rht.mGenFunc), mDeleteFunc(rht.mDeleteFunc), mHandle(rht.mHandle)
{
rht.mHandle = 0u;
}
GLWrapper &operator=(GLWrapper &&rht)
{
if (this != &rht)
{
mGenFunc = rht.mGenFunc;
mDeleteFunc = rht.mDeleteFunc;
std::swap(mHandle, rht.mHandle);
}
return *this;
}
void reset()
{
if (mHandle != 0u)
{
(*mDeleteFunc)(1, &mHandle);
mHandle = 0u;
}
}
GLuint get()
{
if (!mHandle)
{
(*mGenFunc)(1, &mHandle);
}
return mHandle;
}
operator GLuint() { return get(); }
private:
GLGen *mGenFunc;
GLDelete *mDeleteFunc;
GLuint mHandle = 0u;
};
class GLVertexArray : public GLWrapper
{
public:
GLVertexArray() : GLWrapper(&glGenVertexArrays, &glDeleteVertexArrays) {}
};
class GLBuffer : public GLWrapper
{
public:
GLBuffer() : GLWrapper(&glGenBuffers, &glDeleteBuffers) {}
};
class GLTexture : public GLWrapper
{
public:
GLTexture() : GLWrapper(&glGenTextures, &glDeleteTextures) {}
};
class GLFramebuffer : public GLWrapper
{
public:
GLFramebuffer() : GLWrapper(&glGenFramebuffers, &glDeleteFramebuffers) {}
};
class GLMemoryObject : public GLWrapper
{
public:
GLMemoryObject() : GLWrapper(&glCreateMemoryObjectsEXT, &glDeleteMemoryObjectsEXT) {}
};
class GLRenderbuffer : public GLWrapper
{
public:
GLRenderbuffer() : GLWrapper(&glGenRenderbuffers, &glDeleteRenderbuffers) {}
};
class GLSampler : public GLWrapper
{
public:
GLSampler() : GLWrapper(&glGenSamplers, &glDeleteSamplers) {}
};
class GLSemaphore : public GLWrapper
{
public:
GLSemaphore() : GLWrapper(&glGenSemaphoresEXT, &glDeleteSemaphoresEXT) {}
};
class GLTransformFeedback : public GLWrapper
{
public:
GLTransformFeedback() : GLWrapper(&glGenTransformFeedbacks, &glDeleteTransformFeedbacks) {}
};
class GLProgramPipeline : public GLWrapper
{
public:
GLProgramPipeline() : GLWrapper(&glGenProgramPipelines, &glDeleteProgramPipelines) {}
};
class GLQueryEXT : public GLWrapper
{
public:
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;
};
// Prefer ANGLE_GL_PROGRAM for local variables.
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() { return mHandle; }
operator GLuint() { return get(); }
private:
GLuint mHandle;
};
#define ANGLE_GL_EMPTY_PROGRAM(name) \
GLProgram name; \
name.makeEmpty(); \
ASSERT_TRUE(name.valid())
#define ANGLE_GL_PROGRAM(name, vertex, fragment) \
GLProgram name; \
name.makeRaster(vertex, fragment); \
ASSERT_TRUE(name.valid())
#define ANGLE_GL_PROGRAM_WITH_GS(name, vertex, geometry, fragment) \
GLProgram name; \
name.makeRaster(vertex, geometry, fragment); \
ASSERT_TRUE(name.valid())
#define ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(name, vertex, fragment, tfVaryings, bufferMode) \
GLProgram name; \
name.makeRasterWithTransformFeedback(vertex, fragment, tfVaryings, bufferMode); \
ASSERT_TRUE(name.valid())
#define ANGLE_GL_COMPUTE_PROGRAM(name, compute) \
GLProgram name; \
name.makeCompute(compute); \
ASSERT_TRUE(name.valid())
#define ANGLE_GL_BINARY_OES_PROGRAM(name, binary, binaryFormat) \
GLProgram name; \
name.makeBinaryOES(binary, binaryFormat); \
ASSERT_TRUE(name.valid())
#define ANGLE_GL_BINARY_ES3_PROGRAM(name, binary, binaryFormat) \
GLProgram name; \
name.makeBinaryES3(binary, binaryFormat); \
ASSERT_TRUE(name.valid())
} // namespace angle
#endif // ANGLE_TESTS_GL_RAII_H_