수색…


소개

OpenGL 개체를 갖는 다양한 방법의 예는 C ++ RAII에서 작동합니다.

비고

OpenGL 개체의 RAII 캡슐화에는 위험이 있습니다. 가장 피할 수없는 것은 OpenGL 객체가 OpenGL 객체를 만든 OpenGL 컨텍스트와 연결된다는 것입니다. 따라서 C ++ RAII 객체의 파괴는 그 C ++ 객체에 의해 관리되는 OpenGL 객체의 소유권을 공유하는 OpenGL 컨텍스트에서 수행되어야합니다.

이것은 또한 객체를 소유 한 모든 컨텍스트가 파괴되면 기존의 RAII 캡슐화 된 OpenGL 객체가 더 이상 존재하지 않는 객체를 파괴하려고 시도한다는 것을 의미합니다.

이와 같은 문맥 문제를 다루기 위해서는 수동 조치를 취해야합니다.

C ++ 98 / 03에서

C ++ 98/03에서 OpenGL 개체를 캡슐화하려면 C ++ 규칙 3을 준수해야합니다. 이는 복사본 생성자, 복사본 할당 연산자 및 소멸자를 추가하는 것을 의미합니다.

그러나 복사 생성자는 논리적으로 객체를 복사해야합니다. 그리고 OpenGL 객체를 복사하는 것은 간단하지 않습니다. 마찬가지로 중요한 것은 사용자가하지 않으려는 거의 확실한 것입니다.

그래서 우리는 객체를 카피 불가능하게 만들 것입니다 :

class BufferObject
{
public:
    BufferObject(GLenum target, GLsizeiptr size, const void *data, GLenum usage)
    {
        glGenBuffers(1, &object_);
        glBindBuffer(target, object_);
        glBufferData(target, size, data, usage);
        glBindBuffer(target, 0);
    }
    
    ~BufferObject()
    {
        glDeleteBuffers(1, &object_);
    }
    
    //Accessors and manipulators
    void Bind(GLenum target) const {glBindBuffer(target, object_);}
    GLuint GetObject() const {return object_;}

private:
    GLuint object_;
    
    //Prototypes, but no implementation.
    BufferObject(const BufferObject &);
    BufferObject &operator=(const BufferObject &);
};

생성자는 객체를 만들고 버퍼 객체의 데이터를 초기화합니다. 소멸자는 객체를 파괴합니다. 코드 정의 하지 않고 복사 생성자 / 할당을 선언하면 링커에서 코드를 호출하려고하면 오류가 발생합니다. private로 선언하면 BufferObject 멤버 만 호출 할 수 있습니다.

BufferObject 는 생성자에 전달 된 target 보유하지 않습니다. 왜냐하면 OpenGL 버퍼 객체는 처음에 생성 된 객체뿐만 아니라 모든 객체와 함께 사용할 수 있기 때문입니다. 이것은 처음에 작성된 대상에 항상 바인드되어야 하는 텍스처 오브젝트 와 다 (니다.

OpenGL은 다양한 목적을 위해 컨텍스트에 객체를 바인딩하는 것에 매우 의존하기 때문에 RAII 스타일의 범위 객체 바인딩을 사용하는 것이 종종 유용합니다. 서로 다른 객체는 서로 다른 바인딩 요구를 가지기 때문에 (일부는 타겟이 있고 다른 객체는 바인딩이 필요하지 않음), 각 객체마다 하나씩 구현해야합니다.

class BindBuffer
{
public:
    BindBuffer(GLenum target, const BufferObject &buff) : target_(target)
    {
        buff.Bind(target_);
    }
    
    ~BindBuffer()
    {
        glBindBuffer(target_, 0);
    }
    
private:
    GLenum target_;

    //Also non-copyable.
    BindBuffer(const BindBuffer &);
    BindBuffer &operator=(const BindBuffer &);
};

BindBuffer 는 복사가 불가능하기 때문에 복사가 불가능합니다. 바인드하는 BufferObject 액세스는 보관 유지되지 않습니다. 그것은 불필요하기 때문입니다.

C ++ 11 이상

C ++ 11은 RAII로 캡슐화 된 OpenGL 객체의 기능을 향상시키는 도구를 제공합니다. 이동 의미론과 같은 C ++ 11 기능이 없으면 복사 할 수 없기 때문에 이러한 객체를 전달하려는 경우 이러한 객체를 동적으로 할당해야합니다. 이동 지원을 사용하면 복사하지 않고도 표준 값처럼 앞뒤로 전달할 수 있습니다.

class BufferObject
{
public:
    BufferObject(GLenum target, GLsizeiptr size, const void *data, GLenum usage)
    {
        glGenBuffers(1, &object_);
        glBindBuffer(target, object_);
        glBufferData(target, size, data, usage);
        glBindBuffer(target, 0);
    }
    
    //Cannot be copied.
    BufferObject(const BufferObject &) = delete;
    BufferObject &operator=(const BufferObject &) = delete;
    
    //Can be moved
    BufferObject(BufferObject &&other) noexcept : object_(other.Release())
    {}
    
    //Self-assignment is OK with this implementation.
    BufferObject &operator=(BufferObject &&other) noexcept
    {
        Reset(other.Release());
    }
    
    //Destroys the old buffer and claims ownership of a new buffer object.
    //It's OK to call glDeleteBuffers on buffer object 0.
    GLuint Reset(GLuint object = 0)
    {
        glDeleteBuffers(1, &object_);
        object_ = object;
    }
    
    //Relinquishes ownership of the object without destroying it
    GLuint Release()
    {
        GLuint ret = object_;
        object_ = 0;
        return ret;
    }    
    
    ~BufferObject()
    {
        Reset();
    }
    
    //Accessors and manipulators
    void Bind(GLenum target) const {glBindBuffer(target, object_);}
    GLuint GetObject() const {return object_;}

private:
    GLuint object_;
};

이러한 유형은 함수에 의해 반환 될 수 있습니다.

BufferObject CreateStaticBuffer(GLsizeiptr byteSize) {return BufferObject(GL_ARRAY_BUFFER, byteSize, nullptr, GL_STATIC_DRAW);}

어떤 것을 자신의 (암시 적으로 이동 전용) 유형으로 저장할 수 있습니다 :

struct Mesh
{
public:
private:
    //Default member initializer.
    BufferObject buff_ = CreateStaticBuffer(someSize);
};

범위가 지정된 바인더 클래스도 이동 의미를 가질 수 있으므로 바인더가 함수에서 반환되고 C ++ 표준 라이브러리 컨테이너에 저장 될 수 있습니다.

class BindBuffer
{
public:
    BindBuffer(GLenum target, const BufferObject &buff) : target_(target)
    {
        buff.Bind(target_);
    }

    //Non-copyable.
    BindBuffer(const BindBuffer &) = delete;
    BindBuffer &operator=(const BindBuffer &) = delete;
    
    //Move-constructible.
    BindBuffer(BindBuffer &&other) noexcept : target_(other.target_)
    {
        other.target_ = 0;
    }
    
    //Not move-assignable.
    BindBuffer &operator=(BindBuffer &&) = delete;
    
    ~BindBuffer()
    {
        //Only unbind if not moved from.
        if(target_)
            glBindBuffer(target_, 0);
    }
    
private:
    GLenum target_;
};

오브젝트는 움직일 수 있지만 움직일 수는 없습니다. 이 문제는 범위가 지정된 버퍼 바인딩의 리 바인딩을 방지하기위한 것입니다. 설정이 끝나면 설정을 해제 할 수있는 유일한 설정이 이동됩니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow