Подтвердить что ты не робот

Существуют ли какие-либо планы или существующие проекты для переноса API OpenGL на С++?

Стандартные страницы OpenGL заявляют, что OpenGL можно вызывать из C и С++. Однако API, конечно, имеет чистое значение C. Поскольку OpenGL использует, например, множество перечислений, использование enum-классов (из С++ 11) может значительно уменьшить количество ошибок и сделать API более доступным для новичков. Можно видеть, что создаются множество привязок, таких как OpenTK (для С#); создание хорошего С++ API не должно быть намного сложнее.

Я не смог найти ничего, что было бы более чем неясным оберткой, поэтому мои вопросы:

  • Существует ли известная С++-оболочка, использующая средства С++ 11 для OpenGL? и если нет,
  • Что-то вроде этого запланировано кем-то известным (что особенно означает Хронос)?
4b9b3361

Ответ 1

Весь путь OpenGL работает на самом деле не очень хорошо для OOP: http://www.opengl.org/wiki/Common_Mistakes#The_Object_Oriented_Language_Problem

То, что не указано в этой статье, - проблема контекстной близости. В OpenGL все происходит в контексте, поэтому класс "Текстура", чтобы быть правильным, был бы не чем иным, как сглаженным дескриптором, который будет использоваться с контекстом.

Это неверно:

class Texture {
/* ... */

public:
    void bind();
}

Это будет работать, только если текстура была частью активного в настоящее время контекста.

Это тоже не лучше:

class Texture {
/* ... */

public:
    void bind(Context &ctx);
}

Текстура по-прежнему должна быть частью контекста ctx, и она будет работать, только если ctx была активна в данный момент.

Итак, как насчет этого:

class Context {
/* ... */
public:
    void bindTextureToUnit(TextureUnit &tu, Texture &t);
};

Лучше, но все же не корректно, так как контекст должен быть активным в текущем потоке. Вы можете подумать: "О, я просто выброшу исключение, если контекст неактивен". Пожалуйста, не делайте этого.

Так что насчет этого

class ActiveContext : Context {
/* ... */
public:
    void bindTextureToUnit(TextureUnit &tu, Texture &t);

}

Теперь вы закончили тем, что в потоке может быть только один экземпляр ActiveContext. Который заканчивает вас во всех видах беспорядочного беспорядка в низовом потоке.

На самом деле я неоднократно пытался реализовать чистое и разумное сопоставление из состояния OpenGL и объектов в набор классов С++, но всегда есть случаи, когда просто не получается или попадает в ужасный кодовый беспорядок.

ИМХО гораздо лучше не пытаться сопоставить OpenGL API с набором классов С++ (это нельзя сделать разумно), а вместо этого использовать обычный OpenGL API из специализированных классов. Любое управление контекстом OpenGL настолько зависит от программы в вопросах, что оно должно быть специально предназначено для указанной программы.

Ответ 2

Обтекание OpenGL и объектной модели OpenGL - это два разных понятия. Объекты OpenGL можно легко превратить в объекты, чтобы обернуть их функциональность, и действительно, если вы хотите написать рендерер, который может быть создан с помощью, например, OpenGL или D3D, это является строгой необходимостью.

У меня есть классы вроде этого:

    class Device
        class State
    class Buffer
            class BufferUniform
        class BufferVertices
        class BufferIndices
        class BufferArray
    class Texture
        class Texture1d
        class Texture2d
        class Texture3d
        class TextureCubeMap
        class TextureArray
        class TextureRender
        class TextureFrame          
    class Shader
        class ShaderPixel
        class ShaderVertex
        class ShaderGeometry
        class ShaderEvaluator
        class ShaderTessellator
        class ShaderProgram
        class ShaderGenerator
            class ShaderGeneratorParser
            class ShaderGeneratorNode
            class ShaderGeneratorCondition

... и либо D3D, либо OpenGL-версию каждого из них. Renderer <... > создается с одним набором или другим во время компиляции, в зависимости от того, хочу ли я, чтобы D3D или OpenGL выполняли работу.

Ответ 3

Существует ли известная С++-оболочка, использующая средства С++ 11 для OpenGL? и если нет,

Нет. В нем были некоторые попытки.

Что-то вроде этого запланировано кем-либо известным (что особенно означает Хронос)?

Khronos ARB на самом деле не пытается напрямую связаться с нами о предстоящих вещах. Тем не менее, я очень сомневаюсь, что они заботятся об этом.

Как и у кого-либо еще, есть еще некоторые независимые проекты. Но, вообще говоря, люди, которые используют OpenGL, не заинтересованы в этом.

Основные факты таковы: объекты OpenGL напрямую связаны с какой-то глобальной концепцией. А именно, контекст OpenGL. Эти объекты могут обрабатываться только тогда, когда контекст, в котором они существуют внутри (поскольку объекты могут быть разделены между контекстами), активен.

Поэтому любая объектно-ориентированная система С++ должна решить, насколько она отказоустойчива. То есть, какие гарантии, которые он хочет предоставить. Если вы вызываете функцию, которая работает с объектом, насколько вы уверены в том, что этот вызов завершен?

Вот список уровней гарантий, которые можно было бы разумно предоставить:

Полностью анальный

В этом случае вы убедитесь, что каждый вызов функции либо успешно, либо правильно обнаруживает ошибочное состояние и не работает должным образом.

Чтобы снять это, вам нужен явный контекстный объект OpenGL. Каждый объект OpenGL должен быть связан с разделяемой группой между контекстами (или самим конкретным контекстом, если тип объекта не разделяется).

Все функции-члены объекта должны будут принимать объект контекста, который должен быть контекстом, к которому они принадлежат, или членом группы общего доступа для этого контекста. Там должен быть кеш в потоке контекста, чтобы они могли проверить, соответствует ли текущий контекст тому, который им был дан, и сделать его текущим, если это не так.

Когда контекст уничтожается, каждый объект, который полагается на существование этого контекста, должен немедленно стать нефункциональным. Таким образом, каждый такой объект должен иметь доступ к некоторому тегу (например, через std::weak_ptr), чтобы сообщить им, что все вызовы их функций не будут выполнены.

Если объекты будут правильно RAII'd, каждый объект должен быть в состоянии гарантировать, что контекст, который они могут быть уничтожены (то есть: glDelete*), является текущим. И если это не так, им нужно сделать один ток. Таким образом, в основном, каждый объект должен содержать ссылку на допустимый контекст или иначе должен быть способен создать его.

В личной заметке я считаю, что все это мучительно глупо. API не является отказоустойчивым, и он не должен быть. Там много бессмысленной няни и обмена информацией. С++ не является безопасным языком, поэтому он не должен тратить хорошую память и/или производительность, чтобы обеспечить вам такой уровень безопасности.

Сане

Здесь мы избавляемся от проверок безопасности на основе контекста. Пользователь должен убедиться, что соответствующие контексты являются текущими, прежде чем пытаться каким-либо образом использовать какой-либо объект. Это справедливо и для С++. Основная особенность этого API просто приятнее, чем исходный C API.

Объекты OpenGL будут представлять собой стиль RAII, но они также будут иметь функцию "dispose", которая может быть вызвана, если вы хотите, чтобы они очистились, не удаляя соответствующие объекты. Это полезно, если вы закрываете контекст и не хотите запускать и уничтожать все объекты.

Эта система будет в основном предполагать, что вам нужен чистый Direct State Access для этих классов. Поэтому ни одна из модифицирующих функций-членов фактически не связывает объект с контекстом. Они могут достичь этого одним из нескольких способов:

  • Используйте EXT_DSA или эквивалент, если он доступен.
  • Если EXT_DSA или эквивалент недоступен, сохраните измененное состояние и отправьте изменения в следующий раз, когда этот объект привязан.
  • Или просто привяжите его, внесите изменения и отвяжите его.

Некоторые виды модификаций не могут использовать # 2. Например, вызовы glBufferData, glBufferSubData и glTexSubImage*D. Пользователь действительно ожидает, что они произойдут сейчас. Эти функции должны быть названы так, чтобы они отличались от гарантированных необязательных функций.

Любые такие функции привязки не должны прилагать никаких усилий для восстановления предыдущего связанного состояния объекта.

разрешающего

В принципе, существует соответствие 1:1 между функциями-членами С++ и функциями C. Конечно, вы будете использовать перегрузку оператора С++ и, таким образом, уменьшить ненужные изменения функций. Но когда дело доходит до него, вы в значительной степени пишете свой код на С++ так, как вы делали свой C-код.

Объекты могут использовать RAII, но они не будут предоставлять никаких реальных удобств, кроме этого. Функции-члены либо свяжут сам объект, либо ожидают, что вы связали их. Или они будут использовать DSA и сбой, если DSA недоступен.

Зачем беспокоиться?

В конце дня нет ничего, что могло бы выиграть от использования интерфейса С++ для OpenGL. Конечно, вы получите RAII. Ну, вы можете получить RAII просто отлично, используя std::unique_ptr со специальным функтором deleter (да, действительно, это очень возможно). Но помимо некоторого небольшого удобства с API, какую реальную выразительную силу вы получаете, чего у вас не было раньше?

Если вы серьезно относитесь к использованию OpenGL для разработки приложения, вы, вероятно, собираетесь создать систему рендеринга, которая, по сравнению с остальной частью вашего кода, абстрагирует концепции OpenGL. Таким образом, никто не увидит ваш привлекательный интерфейс С++, кроме вашего рендеринга. И ваш рендерер может так же легко использовать OpenGL C API. Зачем создавать рендеринг от абстракции, если он почти ничего не покупает.

И если вы просто играете с OpenGL... что это важно? Просто используйте интерфейс, который у вас есть.