<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[RAII und OpenGL Objekte. Wie?]]></title><description><![CDATA[<p>In OpenGL gibt es viele Objekte die mit einer glGen*/glCreate* Funktion erstellt und mit glDelete* zerstört werden. Das Handle auf diese Objekte ist i.d.R. nur ein GLuint, also keine Objeke im Sinne der OOP.</p>
<p>Mit dem Thema RAII im Hinterkopf bin ich auf diesen Post gestoßen, dabei bitte die akzeptierte Antwort beachten: <a href="http://stackoverflow.com/questions/17161013/raii-wrapper-for-opengl-objects" rel="nofollow">http://stackoverflow.com/questions/17161013/raii-wrapper-for-opengl-objects</a></p>
<p>Der Vorschlag dort ist:</p>
<pre><code>struct VertexArrayObjectTraits  //Entsprechende Traits für Texturen, VBOs u.s.w.
{
  typedef GLuint value_type;
  static value_type Create();
  static void Destroy(value_type);
};

template&lt;typename T&gt;
class OpenGLObject
{
public:
  OpenGLObject() : m_obj(T::Create()) {}
  ~OpenGLObject() {T::Destroy(m_obj);}

  operator typename T::value_type() {return m_obj;}

private:
  typename T::value_type m_obj;
};
</code></pre>
<p>und dann einfach ein solches Objekt anlegen:</p>
<pre><code>OpenGLObject&lt;VertexArrayObjectTraits&gt; obj;
</code></pre>
<p>Das klingt super, macht aber eigentlich nur Kopfschmerzen.<br />
Ein solches Objekt darf nicht einfach bedenkenlos kopiert und zerstört werden, jeder unbedachte Destruktoraufruf einer temporären Kopie würde das OpenGL-Objekt unbrauchbar machen. Also eine NoCopyable-Basisklasse geschrieben, Copyconstructor und Zuweisungsoperator privat gemacht, davon abgeleitet und gut.</p>
<p>Aber, was kann ich nun mit dem Objekt noch anfangen?</p>
<p>Es reicht ja nicht aus, dass ein solches Objekt erzeugt wird, danach finden immer weitere Schritte statt, die man gerne auslagern möchte um sich die Codeverdoppelung zu ersparen.</p>
<p>Nehmen wir mal Vertex Buffer Objects (das sind einfach Speicherbereiche für Vertexdaten), gemäß dem obigen Ansatz mit Traits:</p>
<pre><code>VertexBufferObjectTraits::value_type VertexBufferObjectTraits::Create()
{
	GLuint buffer;
	glGenBuffers(1, &amp;buffer);
	return buffer;
}

void VertexBufferObjectTraits::Destroy(value_type value)
{
	if(glIsBuffer(value))
		glDeleteBuffers(1, &amp;value);
}
</code></pre>
<p>Und dazu möchte man doch gerne eine Art Factory-Funktion, die solche Objekte erstellt und den Buffer beschreibt:</p>
<pre><code>template&lt;typename T&gt;
??? CreateArrayBuffer(const std::vector&lt;T&gt;&amp; vec)
{
	//GLuint buffer;  			//so wars früher
	//glGenBuffers(1, &amp;buffer);

	OpenGLObject&lt;VertexBufferObjectTraits&gt; buffer;
	glBindBuffer(GL_ARRAY_BUFFER, buffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(T) * vec.size(), vec.data(), GL_DYNAMIC_DRAW);
	return buffer;
}
</code></pre>
<p>Offensichtlich kann man das NonCopyable-Objekt nicht mehr zurückgeben.</p>
<p>Was nun?<br />
Als Lösungsansätze kommen mir nur Dinge wie shared_ptr oder unique_ptr und Move-Semantik in den Sinn, womit ich evtl diese Probleme in den Griff kriegen könnte.</p>
<p>Ich habe das Gefühl, je mehr ich solche Prinzipien von modernem C++ befolge, desto mehr Probleme handele ich mir ein nur um diesen Prinzipien überhaupt gerecht zu werden.<br />
Wahrscheinlich verstehe ich die Hintergründe einfach noch nicht genug. Vielleicht kann mich jemand auf die richtige Spur bringen?</p>
<p>Vielleicht noch ganz interessant wie es nun dazu kam, dass ich zerstörbare OpenGL-Objekte mit RAII behandeln wollte. Erstmals hatte ich eine Klasse &quot;GeoObject&quot;. Diese nimmt im Konstruktor Daten entgegen (z.b. Koordinaten (Position, Textur, Farbe)), erstellt ein Vertex Array Object, mehrere Vertex Buffer für die eigentlichen Daten:</p>
<pre><code class="language-cpp">{
	GeoObject::GeoObject(const GeoDataSOA&amp; geoDataSOA)
		: vao(0), vboInd(0), vboPos(0), vboCol(0), vboTex(0)
	{
		glGenVertexArrays(1, &amp;vao);
		glBindVertexArray(vao);

		positionLength = geoDataSOA.Position.size();
		indicesLength = geoDataSOA.Indices.size();

		vboPos = CreateArrayBuffer(geoDataSOA.Position);
		SetAttrib(ShaderAttribute::Vertex, 3);

		if (geoDataSOA.Color.size() &gt; 0)
		{
			vboCol = CreateArrayBuffer(geoDataSOA.Color);
			SetAttrib(ShaderAttribute::Color, 3);
		}

 		if (geoDataSOA.Tex.size() &gt; 0)
		{
 			vboTex = CreateArrayBuffer(geoDataSOA.Tex);
			SetAttrib(ShaderAttribute::Tex0, 2);
		}

		glBindBuffer(GL_ARRAY_BUFFER, 0);

		vboInd = CreateElementBuffer(geoDataSOA.Indices);

		glBindVertexArray(0);
	}
</code></pre>
<p>Und der Destruktor war dieser:</p>
<pre><code class="language-cpp">GeoObject::~GeoObject()
	{
		glDeleteVertexArrays(1, &amp;vao);

		glDeleteBuffers(1, &amp;vboPos);
		glDeleteBuffers(1, &amp;vboInd);

		if(glIsBuffer(vboCol))
			glDeleteBuffers(1, &amp;vboCol);
		if(glIsBuffer(vboTex))
			glDeleteBuffers(1, &amp;vboTex);
	}
</code></pre>
<p>Von eben diesen Lowlevel OpenGL-Objekten, den ganzen GLunits, wollte ich abstrahieren, um sie nicht mehr von Hand mit glDeleteX löschen zu müssen.<br />
Und später dann auf Texturen und anderes ähnlich verwalten.</p>
<p>Aber ja wie gesagt, das verursacht nur mehr Probleme</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/332252/raii-und-opengl-objekte-wie</link><generator>RSS for Node</generator><lastBuildDate>Tue, 28 Apr 2026 10:56:52 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/332252.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 17 Apr 2015 18:13:14 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to RAII und OpenGL Objekte. Wie? on Fri, 17 Apr 2015 18:13:14 GMT]]></title><description><![CDATA[<p>In OpenGL gibt es viele Objekte die mit einer glGen*/glCreate* Funktion erstellt und mit glDelete* zerstört werden. Das Handle auf diese Objekte ist i.d.R. nur ein GLuint, also keine Objeke im Sinne der OOP.</p>
<p>Mit dem Thema RAII im Hinterkopf bin ich auf diesen Post gestoßen, dabei bitte die akzeptierte Antwort beachten: <a href="http://stackoverflow.com/questions/17161013/raii-wrapper-for-opengl-objects" rel="nofollow">http://stackoverflow.com/questions/17161013/raii-wrapper-for-opengl-objects</a></p>
<p>Der Vorschlag dort ist:</p>
<pre><code>struct VertexArrayObjectTraits  //Entsprechende Traits für Texturen, VBOs u.s.w.
{
  typedef GLuint value_type;
  static value_type Create();
  static void Destroy(value_type);
};

template&lt;typename T&gt;
class OpenGLObject
{
public:
  OpenGLObject() : m_obj(T::Create()) {}
  ~OpenGLObject() {T::Destroy(m_obj);}

  operator typename T::value_type() {return m_obj;}

private:
  typename T::value_type m_obj;
};
</code></pre>
<p>und dann einfach ein solches Objekt anlegen:</p>
<pre><code>OpenGLObject&lt;VertexArrayObjectTraits&gt; obj;
</code></pre>
<p>Das klingt super, macht aber eigentlich nur Kopfschmerzen.<br />
Ein solches Objekt darf nicht einfach bedenkenlos kopiert und zerstört werden, jeder unbedachte Destruktoraufruf einer temporären Kopie würde das OpenGL-Objekt unbrauchbar machen. Also eine NoCopyable-Basisklasse geschrieben, Copyconstructor und Zuweisungsoperator privat gemacht, davon abgeleitet und gut.</p>
<p>Aber, was kann ich nun mit dem Objekt noch anfangen?</p>
<p>Es reicht ja nicht aus, dass ein solches Objekt erzeugt wird, danach finden immer weitere Schritte statt, die man gerne auslagern möchte um sich die Codeverdoppelung zu ersparen.</p>
<p>Nehmen wir mal Vertex Buffer Objects (das sind einfach Speicherbereiche für Vertexdaten), gemäß dem obigen Ansatz mit Traits:</p>
<pre><code>VertexBufferObjectTraits::value_type VertexBufferObjectTraits::Create()
{
	GLuint buffer;
	glGenBuffers(1, &amp;buffer);
	return buffer;
}

void VertexBufferObjectTraits::Destroy(value_type value)
{
	if(glIsBuffer(value))
		glDeleteBuffers(1, &amp;value);
}
</code></pre>
<p>Und dazu möchte man doch gerne eine Art Factory-Funktion, die solche Objekte erstellt und den Buffer beschreibt:</p>
<pre><code>template&lt;typename T&gt;
??? CreateArrayBuffer(const std::vector&lt;T&gt;&amp; vec)
{
	//GLuint buffer;  			//so wars früher
	//glGenBuffers(1, &amp;buffer);

	OpenGLObject&lt;VertexBufferObjectTraits&gt; buffer;
	glBindBuffer(GL_ARRAY_BUFFER, buffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(T) * vec.size(), vec.data(), GL_DYNAMIC_DRAW);
	return buffer;
}
</code></pre>
<p>Offensichtlich kann man das NonCopyable-Objekt nicht mehr zurückgeben.</p>
<p>Was nun?<br />
Als Lösungsansätze kommen mir nur Dinge wie shared_ptr oder unique_ptr und Move-Semantik in den Sinn, womit ich evtl diese Probleme in den Griff kriegen könnte.</p>
<p>Ich habe das Gefühl, je mehr ich solche Prinzipien von modernem C++ befolge, desto mehr Probleme handele ich mir ein nur um diesen Prinzipien überhaupt gerecht zu werden.<br />
Wahrscheinlich verstehe ich die Hintergründe einfach noch nicht genug. Vielleicht kann mich jemand auf die richtige Spur bringen?</p>
<p>Vielleicht noch ganz interessant wie es nun dazu kam, dass ich zerstörbare OpenGL-Objekte mit RAII behandeln wollte. Erstmals hatte ich eine Klasse &quot;GeoObject&quot;. Diese nimmt im Konstruktor Daten entgegen (z.b. Koordinaten (Position, Textur, Farbe)), erstellt ein Vertex Array Object, mehrere Vertex Buffer für die eigentlichen Daten:</p>
<pre><code class="language-cpp">{
	GeoObject::GeoObject(const GeoDataSOA&amp; geoDataSOA)
		: vao(0), vboInd(0), vboPos(0), vboCol(0), vboTex(0)
	{
		glGenVertexArrays(1, &amp;vao);
		glBindVertexArray(vao);

		positionLength = geoDataSOA.Position.size();
		indicesLength = geoDataSOA.Indices.size();

		vboPos = CreateArrayBuffer(geoDataSOA.Position);
		SetAttrib(ShaderAttribute::Vertex, 3);

		if (geoDataSOA.Color.size() &gt; 0)
		{
			vboCol = CreateArrayBuffer(geoDataSOA.Color);
			SetAttrib(ShaderAttribute::Color, 3);
		}

 		if (geoDataSOA.Tex.size() &gt; 0)
		{
 			vboTex = CreateArrayBuffer(geoDataSOA.Tex);
			SetAttrib(ShaderAttribute::Tex0, 2);
		}

		glBindBuffer(GL_ARRAY_BUFFER, 0);

		vboInd = CreateElementBuffer(geoDataSOA.Indices);

		glBindVertexArray(0);
	}
</code></pre>
<p>Und der Destruktor war dieser:</p>
<pre><code class="language-cpp">GeoObject::~GeoObject()
	{
		glDeleteVertexArrays(1, &amp;vao);

		glDeleteBuffers(1, &amp;vboPos);
		glDeleteBuffers(1, &amp;vboInd);

		if(glIsBuffer(vboCol))
			glDeleteBuffers(1, &amp;vboCol);
		if(glIsBuffer(vboTex))
			glDeleteBuffers(1, &amp;vboTex);
	}
</code></pre>
<p>Von eben diesen Lowlevel OpenGL-Objekten, den ganzen GLunits, wollte ich abstrahieren, um sie nicht mehr von Hand mit glDeleteX löschen zu müssen.<br />
Und später dann auf Texturen und anderes ähnlich verwalten.</p>
<p>Aber ja wie gesagt, das verursacht nur mehr Probleme</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2450681</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2450681</guid><dc:creator><![CDATA[Salzwasser]]></dc:creator><pubDate>Fri, 17 Apr 2015 18:13:14 GMT</pubDate></item><item><title><![CDATA[Reply to RAII und OpenGL Objekte. Wie? on Fri, 17 Apr 2015 18:31:28 GMT]]></title><description><![CDATA[<p>Nimm doch einfach unique_ptr, anstatt deine Ressourcenverwalter von Hand zu programmieren. Das macht genau das gleiche, aber garantiert fehlerfrei und sollte mit einem Schlag all deine Probleme lösen.</p>
<blockquote>
<p>Ich habe das Gefühl, je mehr ich solche Prinzipien von modernem C++ befolge, desto mehr Probleme handele ich mir ein nur um diesen Prinzipien überhaupt gerecht zu werden.<br />
Wahrscheinlich verstehe ich die Hintergründe einfach noch nicht genug. Vielleicht kann mich jemand auf die richtige Spur bringen?</p>
</blockquote>
<p>Ich habe irgendwie den Eindruck, dass du immer noch versuchst, C zu programmieren. Zwar nicht das gefürchtete &quot;C mit Klassen&quot;, sondern &quot;C mit RAII&quot;, aber das ist eben immer noch nicht C++.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2450687</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2450687</guid><dc:creator><![CDATA[SeppJ]]></dc:creator><pubDate>Fri, 17 Apr 2015 18:31:28 GMT</pubDate></item><item><title><![CDATA[Reply to RAII und OpenGL Objekte. Wie? on Fri, 17 Apr 2015 18:37:26 GMT]]></title><description><![CDATA[<p>SeppJ schrieb:</p>
<blockquote>
<p>Nimm doch einfach unique_ptr, anstatt deine Ressourcenverwalter von Hand zu programmieren. Das macht genau das gleiche, aber garantiert fehlerfrei und sollte mit einem Schlag all deine Probleme lösen.</p>
</blockquote>
<p>Kannst du das bitte etwas ausführen?<br />
Mir ist unique_ptr bekannt, aber offenbar nicht die adäquate Anwendung auf mein Problem.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2450691</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2450691</guid><dc:creator><![CDATA[Salzwasser]]></dc:creator><pubDate>Fri, 17 Apr 2015 18:37:26 GMT</pubDate></item><item><title><![CDATA[Reply to RAII und OpenGL Objekte. Wie? on Fri, 17 Apr 2015 18:41:11 GMT]]></title><description><![CDATA[<p>SeppJ schrieb:</p>
<blockquote>
<p>Ich habe irgendwie den Eindruck, dass du immer noch versuchst, C zu programmieren. Zwar nicht das gefürchtete &quot;C mit Klassen&quot;, sondern &quot;C mit RAII&quot;, aber das ist eben immer noch nicht C++.</p>
</blockquote>
<p>Nicht C, ich komme aus der C#-Welt.<br />
&quot;C mit RAII&quot; aber kein richtiges C++, nun, bitte verliere noch ein paar Worte dazu.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2450693</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2450693</guid><dc:creator><![CDATA[Salzwasser]]></dc:creator><pubDate>Fri, 17 Apr 2015 18:41:11 GMT</pubDate></item><item><title><![CDATA[Reply to RAII und OpenGL Objekte. Wie? on Fri, 17 Apr 2015 18:59:26 GMT]]></title><description><![CDATA[<p>Salzwasser schrieb:</p>
<blockquote>
<p>Kannst du das bitte etwas ausführen?<br />
Mir ist unique_ptr bekannt, aber offenbar nicht die adäquate Anwendung auf mein Problem.</p>
</blockquote>
<pre><code>struct vbo_deleter
{
   using pointer = GLuint;

   void operator()(pointer p) noexcept
   {
     // cleanup
   }
};

std::unique_ptr&lt;GLuint, vbo_deleter&gt; ptr(a_vbo);
</code></pre>
<p>Edit: Ich hoffe für sowas wirklich auf dieses Proposal o.ä <a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n3949.pdf" rel="nofollow">http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n3949.pdf</a>.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2450697</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2450697</guid><dc:creator><![CDATA[Nathan]]></dc:creator><pubDate>Fri, 17 Apr 2015 18:59:26 GMT</pubDate></item><item><title><![CDATA[Reply to RAII und OpenGL Objekte. Wie? on Sat, 18 Apr 2015 09:49:44 GMT]]></title><description><![CDATA[<p>Die Frage ist, ob sich ein generischer Ansatz ueberhaupt lohnt. Ueblicherweise braucht man eine OpenGL version und muss keinen Wrapper um die gesamte API mit allem legacy-kram schreiben. Das sind aber nur jeweils ein paar verschiedene Objekte, bei OpenGL 3 bleibt man vermutlich unter 10 und findet auch vielleicht mal eine Ausnahme, die sich nicht exakt in gen- und delete-funktion aufteilen laesst.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2450745</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2450745</guid><dc:creator><![CDATA[Marthog]]></dc:creator><pubDate>Sat, 18 Apr 2015 09:49:44 GMT</pubDate></item><item><title><![CDATA[Reply to RAII und OpenGL Objekte. Wie? on Sat, 18 Apr 2015 18:58:41 GMT]]></title><description><![CDATA[<p>Nathan schrieb:</p>
<blockquote>
<pre><code>struct vbo_deleter
{
   using pointer = GLuint;

   void operator()(pointer p) noexcept
   {
     // cleanup
   }
};

std::unique_ptr&lt;GLuint, vbo_deleter&gt; ptr(a_vbo);
</code></pre>
</blockquote>
<p>Konkret so?</p>
<pre><code>struct del 
{ 
	void operator()(GLuint* p)  
	{ 
		cout&lt;&lt;&quot;deleter C\n&quot;;
		glDeleteBuffers(1, p);
	} 
}; 

void trashtest()
{
	GLuint b;
	glGenBuffers(1, &amp;b);
	unique_ptr&lt;GLuint, del&gt; ptr(&amp;b);   
}
</code></pre>
<p>Die Konstruktion sieht etwas schräg aus.<br />
Oder habe ich was falsch verstanden?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2450801</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2450801</guid><dc:creator><![CDATA[Salzwasser]]></dc:creator><pubDate>Sat, 18 Apr 2015 18:58:41 GMT</pubDate></item></channel></rss>