QRhiBuffer Class
Vertex-, Index- oder einheitliche (konstante) Pufferressource. Mehr...
Kopfzeile: | #include <rhi/qrhi.h> |
CMake: | find_package(Qt6 REQUIRED COMPONENTS Gui) target_link_libraries(mytarget PRIVATE Qt6::GuiPrivate) |
qmake: | QT += gui-private |
Since: | Qt 6.6 |
Vererbt: | QRhiResource |
Öffentliche Typen
struct | NativeBuffer |
enum | Type { Immutable, Static, Dynamic } |
enum | UsageFlag { VertexBuffer, IndexBuffer, UniformBuffer, StorageBuffer } |
flags | UsageFlags |
Öffentliche Funktionen
virtual char * | beginFullDynamicBufferUpdateForCurrentFrame() |
virtual bool | create() = 0 |
virtual void | endFullDynamicBufferUpdateForCurrentFrame() |
virtual QRhiBuffer::NativeBuffer | nativeBuffer() |
void | setSize(quint32 sz) |
void | setType(QRhiBuffer::Type t) |
void | setUsage(QRhiBuffer::UsageFlags u) |
quint32 | size() const |
QRhiBuffer::Type | type() const |
QRhiBuffer::UsageFlags | usage() const |
Reimplementierte öffentliche Funktionen
virtual QRhiResource::Type | resourceType() const override |
Detaillierte Beschreibung
Hinweis: Dies ist eine RHI-API mit begrenzten Kompatibilitätsgarantien, siehe QRhi für Details.
Ein QRhiBuffer kapselt null, ein oder mehrere native Pufferobjekte (wie z. B. VkBuffer
oder MTLBuffer
). Bei einigen Grafik-APIs und Backends verwenden bestimmte Arten von Puffern möglicherweise überhaupt kein natives Pufferobjekt (z. B. OpenGL, wenn keine einheitlichen Pufferobjekte verwendet werden), aber dies ist für den Benutzer der QRhiBuffer-API transparent. Ebenso ist die Tatsache, dass einige Puffertypen zwei oder drei native Puffer darunter verwenden können, um eine effiziente Inhaltsaktualisierung pro Frame zu ermöglichen, ohne die GPU-Pipeline zu blockieren, für die Anwendungen und Bibliotheken weitgehend unsichtbar.
Eine QRhiBuffer-Instanz wird immer durch den Aufruf von the QRhi's newBuffer() function erstellt. Dadurch werden keine nativen Grafikressourcen erzeugt. Rufen Sie dazu create() auf, nachdem Sie die entsprechenden Optionen wie Typ, Verwendungsflags und Größe festgelegt haben, obwohl diese in den meisten Fällen bereits anhand der an newBuffer() übergebenen Argumente festgelegt sind.
Beispiel für die Verwendung
Erzeugen eines einheitlichen Puffers für einen Shader, bei dem der einheitliche GLSL-Block ein einzelnes mat4
-Mitglied enthält, und Aktualisieren des Inhalts:
QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64); if (!ubuf->create()) { error(); } QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); QMatrix4x4 mvp; // ... set up the modelview-projection matrix batch->updateDynamicBuffer(ubuf, 0, 64, mvp.constData()); // ... commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call
Ein Beispiel für die Erstellung eines Puffers mit Vertex-Daten:
const float vertices[] = { -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 1.0f }; QRhiBuffer *vbuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices)); if (!vbuf->create()) { error(); } QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); batch->uploadStaticBuffer(vbuf, vertices); // ... commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call
Ein Indexpuffer:
static const quint16 indices[] = { 0, 1, 2 }; QRhiBuffer *ibuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(indices)); if (!ibuf->create()) { error(); } QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); batch->uploadStaticBuffer(ibuf, indices); // ... commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call
Gemeinsame Muster
Ein Aufruf von create() zerstört alle vorhandenen nativen Ressourcen, wenn create() zuvor erfolgreich aufgerufen wurde. Wenn diese nativen Ressourcen noch von einem laufenden Frame verwendet werden (d. h., es besteht die Möglichkeit, dass sie noch von der GPU gelesen werden), wird die Zerstörung dieser Ressourcen automatisch aufgeschoben. Ein sehr gängiges und bequemes Muster, um die Größe eines bereits initialisierten Puffers sicher zu erhöhen, ist daher das folgende. In der Praxis wird dadurch ein ganzer Satz nativer Ressourcen darunter erzeugt, so dass es nicht unbedingt eine billige Operation ist, aber es ist bequemer und immer noch schneller als die Alternativen, weil dadurch, dass das buf
-Objekt selbst nicht zerstört wird, alle Referenzen darauf in anderen Datenstrukturen gültig bleiben (z. B. in jeder QRhiShaderResourceBinding, von der aus der QRhiBuffer referenziert wird).
if (buf->size() < newSize) { buf->setSize(newSize); if (!buf->create()) { error(); } } // continue using buf, fill it with new data
Bei der Arbeit mit einheitlichen Puffern wird es manchmal notwendig sein, Daten für mehrere Zeichenaufrufe aus Effizienzgründen in einem einzigen Puffer zu kombinieren. Beachten Sie die Ausrichtungsanforderungen: Bei einigen Grafik-APIs müssen die Offsets für einen einheitlichen Puffer auf 256 Bytes ausgerichtet werden. Dies gilt sowohl für QRhiShaderResourceBinding als auch für die dynamischen Offsets, die an setShaderResources() übergeben werden. Verwenden Sie die Funktionen ubufAlignment() und ubufAligned(), um portablen Code zu erstellen. Im Folgenden finden Sie ein Beispiel für mehrere (N
) Zeichenaufrufe mit der gleichen Pipeline und Geometrie, aber mit unterschiedlichen Daten in den einheitlichen Puffern, die am Bindungspunkt 0 exponiert sind. Dies setzt voraus, dass der Puffer über uniformBufferWithDynamicOffset() exponiert ist, was die Übergabe einer QRhiCommandBuffer::DynamicOffset Liste an setShaderResources() ermöglicht.
const int N = 2; const int UB_SIZE = 64 + 4; // assuming a uniform block with { mat4 matrix; float opacity; } const int ONE_UBUF_SIZE = rhi->ubufAligned(UB_SIZE); const int TOTAL_UBUF_SIZE = N * ONE_UBUF_SIZE; QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, TOTAL_UBUF_SIZE); if (!ubuf->create()) { error(); } QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); for (int i = 0; i < N; ++i) { batch->updateDynamicBuffer(ubuf, i * ONE_UBUF_SIZE, 64, matrix.constData()); batch->updateDynamicBuffer(ubuf, i * ONE_UBUF_SIZE + 64, 4, &opacity); } // ... // beginPass(), set pipeline, etc., and then: for (int i = 0; i < N; ++i) { QRhiCommandBuffer::DynamicOffset dynOfs[] = { { 0, i * ONE_UBUF_SIZE } }; cb->setShaderResources(srb, 1, dynOfs); cb->draw(36); }
Siehe auch QRhiResourceUpdateBatch, QRhi, und QRhiCommandBuffer.
Dokumentation der Mitgliedstypen
enum QRhiBuffer::Type
Gibt den Speichertyp der Pufferressource an.
Konstante | Wert | Beschreibung |
---|---|---|
QRhiBuffer::Immutable | 0 | Gibt an, dass sich die Daten nach dem ersten Hochladen voraussichtlich nicht mehr ändern werden. Unter der Haube werden solche Pufferressourcen typischerweise im gerätelokalen (GPU-)Speicher platziert (auf Systemen, wo anwendbar). Das Hochladen neuer Daten ist möglich, kann aber teuer sein. Das Hochladen erfolgt in der Regel durch Kopieren in einen separaten, für den Host sichtbaren Bereitstellungspuffer, von dem aus eine GPU-Puffer-zu-Puffer-Kopie in den eigentlichen reinen GPU-Puffer ausgegeben wird. |
QRhiBuffer::Static | 1 | Zeigt an, dass sich die Daten voraussichtlich nur selten ändern werden. Wird in der Regel im gerätelokalen (GPU-)Speicher abgelegt, wo dies möglich ist. Bei Backends, bei denen für den Host sichtbare Staging-Puffer für das Hochladen verwendet werden, bleiben die Staging-Puffer für diesen Typ, anders als bei Immutable, erhalten, so dass nachfolgende Uploads nicht an Leistung einbüßen. Häufige Aktualisierungen, insbesondere Aktualisierungen in aufeinanderfolgenden Frames, sollten vermieden werden. |
QRhiBuffer::Dynamic | 2 | Zeigt an, dass sich die Daten voraussichtlich häufig ändern werden. Nicht empfohlen für große Puffer. In der Regel durch den sichtbaren Speicher des Hosts in zwei Kopien gesichert, um Änderungen zu ermöglichen, ohne die Grafikpipeline zu blockieren. Die doppelte Pufferung wird für die Anwendungen transparent verwaltet und ist in der API in keiner Form sichtbar. Dies ist der empfohlene und bei einigen Backends auch der einzig mögliche Typ für Puffer mit UniformBuffer Verwendung. |
enum QRhiBuffer::UsageFlag
flags QRhiBuffer::UsageFlags
Flag-Werte, die angeben, wie der Puffer verwendet werden soll.
Konstante | Wert | Beschreibung |
---|---|---|
QRhiBuffer::VertexBuffer | 1 << 0 | Vertex-Puffer. Damit kann die QRhiBuffer in setVertexInput() verwendet werden. |
QRhiBuffer::IndexBuffer | 1 << 1 | Index-Puffer. Damit kann der QRhiBuffer in setVertexInput() verwendet werden. |
QRhiBuffer::UniformBuffer | 1 << 2 | Einheitlicher Puffer (auch konstanter Puffer genannt). Dies ermöglicht die Verwendung von QRhiBuffer in Kombination mit UniformBuffer. Wenn NonDynamicUniformBuffers als nicht unterstützt gemeldet wird, kann diese Verwendung nur mit dem Typ Dynamic kombiniert werden. |
QRhiBuffer::StorageBuffer | 1 << 3 | Speicherpuffer. Dies ermöglicht die Verwendung von QRhiBuffer in Kombination mit BufferLoad, BufferStore oder BufferLoadStore. Diese Verwendung kann nur mit den Typen Immutable oder Static kombiniert werden und ist nur verfügbar, wenn Compute feature als unterstützt gemeldet wird. |
Der Typ UsageFlags ist ein Typedef für QFlags<UsageFlag>. Er speichert eine ODER-Kombination von UsageFlag-Werten.
Dokumentation der Mitgliedsfunktionen
[virtual]
char *QRhiBuffer::beginFullDynamicBufferUpdateForCurrentFrame()
Gibt einen Zeiger auf einen Speicherblock mit den Daten des sichtbaren Host-Puffers zurück.
Dies ist eine Abkürzung für mittelgroße bis große dynamische einheitliche Puffer, deren gesamter Inhalt (oder zumindest alle Regionen, die von den Shadern im aktuellen Frame gelesen werden) in jedem Frame geändert wird und der QRhiResourceUpdateBatch-basierte Aktualisierungsmechanismus aufgrund der Menge an Datenkopien als zu schwerfällig angesehen wird.
Auf den Aufruf dieser Funktion muss schließlich ein Aufruf von endFullDynamicUniformBufferUpdateForCurrentFrame() folgen, bevor ein Render- oder Berechnungsdurchlauf aufgezeichnet wird, der sich auf diesen Puffer stützt.
Warnung: Die Aktualisierung von Daten über diese Methode ist nicht kompatibel mit QRhiResourceUpdateBatch-basierten Updates und Readbacks. Unerwartetes Verhalten kann auftreten, wenn versucht wird, die beiden Aktualisierungsmodelle für denselben Puffer zu kombinieren. Ebenso sind die auf diesem direkten Weg aktualisierten Daten je nach Backend möglicherweise nicht für readBackBuffer operations sichtbar.
Warnung: Wenn Pufferdaten über diese Methode aktualisiert werden, muss die Aktualisierung in jedem Frame erfolgen, da sonst Backends, die eine doppelte oder dreifache Pufferung von Ressourcen durchführen, zu unerwartetem Verhalten führen können.
Warnung: Teilweise Aktualisierungen sind mit diesem Ansatz nicht möglich, da einige Backends eine Strategie wählen, bei der der vorherige Inhalt des Puffers beim Aufruf dieser Funktion verloren geht. Daten müssen in alle Regionen geschrieben werden, die von Shadern in dem aktuell vorbereiteten Frame gelesen werden.
Warnung: Diese Funktion kann nur während der Aufzeichnung eines Frames aufgerufen werden, also zwischen QRhi::beginFrame() und QRhi::endFrame().
Warnung: Diese Funktion kann nur bei dynamischen Puffern aufgerufen werden.
[pure virtual]
bool QRhiBuffer::create()
Erzeugt die entsprechenden nativen Grafikressourcen. Wenn aufgrund eines früheren create() ohne entsprechende destroy() bereits Ressourcen vorhanden sind, wird destroy() implizit zuerst aufgerufen.
Gibt bei Erfolg true
zurück, bei einem fehlgeschlagenen Grafikvorgang false
. Unabhängig vom Rückgabewert ist der Aufruf von destroy() immer sicher.
[virtual]
void QRhiBuffer::endFullDynamicBufferUpdateForCurrentFrame()
Wird aufgerufen, wenn der gesamte Inhalt der Pufferdaten in dem von beginFullDynamicBufferUpdateForCurrentFrame() zurückgegebenen Speicherblock aktualisiert wurde.
[virtual]
QRhiBuffer::NativeBuffer QRhiBuffer::nativeBuffer()
Gibt die zugrunde liegenden nativen Ressourcen für diesen Puffer zurück. Der zurückgegebene Wert ist leer, wenn die zugrundeliegenden nativen Ressourcen vom Backend nicht unterstützt werden.
Ein QRhiBuffer kann von mehreren nativen Pufferobjekten unterstützt werden, je nach type() und dem verwendeten QRhi Backend. Wenn dies der Fall ist, werden alle diese Objekte im Array objects in der zurückgegebenen Struktur zurückgegeben, wobei slotCount die Anzahl der nativen Pufferobjekte angibt. Während recording a frame, QRhi::currentFrameSlot() verwendet werden kann, um festzustellen, welcher der nativen Puffer QRhi für Operationen verwendet wird, die von diesem QRhiBuffer innerhalb des aufgezeichneten Frames lesen oder schreiben.
In einigen Fällen wird ein QRhiBuffer überhaupt nicht durch ein natives Pufferobjekt unterstützt. In diesem Fall wird slotCount auf 0 gesetzt und es werden keine gültigen nativen Objekte zurückgegeben. Dies ist kein Fehler und ist durchaus zulässig, wenn ein bestimmtes Backend keine nativen Puffer für QRhiBuffers mit bestimmten Typen oder Verwendungen verwendet.
Hinweis: Sei dir bewusst, dass QRhi Backends verschiedene Puffer-Aktualisierungsstrategien verwenden können. Im Gegensatz zu Texturen, bei denen das Hochladen von Bilddaten immer die Aufzeichnung eines Buffer-to-Image- (oder ähnlichen) Kopierbefehls im Befehlspuffer bedeutet, können Puffer, insbesondere dynamische und UniformBuffer, auf viele verschiedene Arten funktionieren. Zum Beispiel kann ein QRhiBuffer mit der Verwendungsart UniformBuffer überhaupt nicht durch ein natives Pufferobjekt unterstützt werden, wenn einheitliche Puffer von einem bestimmten Backend und einer Grafik-API nicht verwendet oder unterstützt werden. Es gibt auch Unterschiede in der Art, wie Daten in den Puffer geschrieben werden, und in der Art des verwendeten Sicherungsspeichers. Bei Puffern, die durch sichtbaren Speicher des Hosts gesichert sind, garantiert der Aufruf dieser Funktion, dass anstehende Schreibvorgänge des Hosts für alle zurückgegebenen nativen Puffer ausgeführt werden.
Siehe auch QRhi::currentFrameSlot() und QRhi::FramesInFlight.
[override virtual]
QRhiResource::Type QRhiBuffer::resourceType() const
Reimplements: QRhiResource::resourceType() const.
Gibt den Ressourcentyp zurück.
void QRhiBuffer::setSize(quint32 sz)
Legt die Größe des Puffers in Bytes fest. Die Größe wird normalerweise in QRhi::newBuffer() angegeben, so dass diese Funktion nur verwendet wird, wenn die Größe geändert werden muss. Wie bei anderen Setzern wird die Größe nur beim Aufruf von create() wirksam, und für bereits erstellte Puffer bedeutet dies die Freigabe der vorherigen nativen Ressource und die Erstellung neuer Ressourcen unter der Haube.
Backends können sich dafür entscheiden, Puffer zuzuweisen, die größer sind als sz, um die Ausrichtungsanforderungen zu erfüllen. Dies bleibt vor den Anwendungen verborgen, und size() wird immer die in sz angeforderte Größe melden.
Siehe auch size().
void QRhiBuffer::setType(QRhiBuffer::Type t)
Setzt den Typ des Puffers auf t.
Siehe auch type().
void QRhiBuffer::setUsage(QRhiBuffer::UsageFlags u)
Setzt die Verwendungskennzeichen des Puffers auf u.
Siehe auch usage().
quint32 QRhiBuffer::size() const
Gibt die Größe des Puffers in Bytes zurück.
Dies ist immer der Wert, der an setSize() oder QRhi::newBuffer() übergeben wurde. Intern können die nativen Puffer größer sein, wenn dies von der zugrundeliegenden Grafik-API verlangt wird.
Siehe auch setSize().
QRhiBuffer::Type QRhiBuffer::type() const
Gibt den Puffertyp zurück.
Siehe auch setType().
QRhiBuffer::UsageFlags QRhiBuffer::usage() const
Gibt die Verwendungskennzeichen des Puffers zurück.
Siehe auch setUsage().
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.