Wie funktioniert die Hardware-Texturkomprimierung?


13

Dass es die Daten im Vergleich zum Pixelarray komprimiert, liegt auf der Hand.

Aber was unterscheidet es von normaler Komprimierung (wie PNG, JPEG)?


Was ist "normale Komprimierung" - Dinge wie JPEG und PNG? Fragen Sie nach den Unterschieden zwischen diesen und Hardware-unterstützten Formaten wie DXT und ASTC?
Nathan Reed

6
(Endlich ein Thema, über das ich ein bisschen Bescheid weiß!) Was es von PNG / JPEG unterscheidet, ist der Direktzugriff. Wenn Sie auf Texel (XY) zugreifen möchten, können Sie schnell feststellen, wie wenig Daten für die Erstellung dieses Texels erforderlich sind. JPG oder PNG erfordern möglicherweise die Dekomprimierung aller Daten! Die Abschnitte 1 und 2 des Wikipedia-Artikels sind eine gute Zusammenfassung.
Simon F

Wie SimonF schrieb. Dies ist eine äußerst umfassende Frage, und die Antwort hängt davon ab, für welchen Typ Sie sich interessieren. Haben Sie sich die Spezifikation für z. B. DXT angesehen?
Imallett

Antworten:


24

Wie in Simons Kommentar angedeutet, besteht ein Hauptunterschied zwischen der Hardware-Texturkomprimierung und anderen häufig verwendeten Bildkomprimierungen darin, dass erstere keine Entropiecodierung verwenden. Entropiecodierung ist die Verwendung kürzerer Bitfolgen, um häufig vorkommende oder sich wiederholende Muster in den Quelldaten darzustellen - wie in Containerformaten wie ZIP, vielen gängigen Bildformaten wie GIF, JPEG und PNG sowie in vielen gängigen Audioformaten und Videoformate.

Die Entropiecodierung ist gut für die Komprimierung aller Arten von Daten geeignet, erzeugt jedoch automatisch ein variables Komprimierungsverhältnis. Einige Bereiche des Bildes enthalten möglicherweise wenig Details (oder die Details werden vom verwendeten Codierungsmodell gut vorhergesagt) und erfordern nur sehr wenige Bits, andere Bereiche enthalten möglicherweise komplexe Details, für deren Codierung mehr Bits erforderlich sind. Dies erschwert die Implementierung von Direktzugriffen, da es keinen einfachen Weg gibt, um zu berechnen, wo in den komprimierten Daten sich das Pixel bei gegebenem ( xy) befindet) Koordinaten. Außerdem sind die meisten Entropiecodierungsschemata statusbehaftet, sodass es nicht möglich ist, die Decodierung einfach an einer beliebigen Stelle im Stream zu starten. Sie müssen von vorne beginnen, um den richtigen Zustand aufzubauen. Für die Texturabtastung ist jedoch ein wahlfreier Zugriff erforderlich, da ein Shader jederzeit von jeder Stelle in einer Textur abtasten kann.

Anstelle der Entropiecodierung werden bei der Hardwarekomprimierung blockbasierte Schemata mit festem Verhältnis verwendet. Beispielsweise wird bei der DXT / BCn-Komprimierung die Textur in 4 × 4-Pixelblöcke aufgeteilt, von denen jeder entweder in 64 oder 128 Bit codiert ist (je nachdem, welches Format ausgewählt wird). In ASTC verwenden verschiedene Formate Blockgrößen von 4 × 4 bis 12 × 12, und alle Blöcke werden in 128 Bit codiert. Die Details, wie die Bits die Bilddaten darstellen, variieren zwischen den Formaten (und können sogar von einem Block zum nächsten innerhalb desselben Bildes variieren), aber da das Verhältnis fest ist, kann die Hardware leicht berechnen, wo im Speicher der Block zu finden ist enthält ein gegebenes ( x , y ) Pixel und jeder Block ist in sich geschlossen, so dass er unabhängig von anderen Blöcken decodiert werden kann.

Eine weitere Überlegung bei der Hardware-Texturkomprimierung besteht darin, dass die Dekodierung effizient in Hardware implementiert werden sollte. Dies bedeutet, dass schwere mathematische Operationen und ein komplexer Datenfluss stark benachteiligt sind. Die BCn-Formate können zum Beispiel dekodiert werden, indem eine Handvoll 8-Bit-Ganzzahl-Rechenoperationen pro Block ausgeführt werden, um eine kleine Nachschlagetabelle zu füllen, und dann nur der entsprechende Tabelleneintrag pro Pixel nachgeschlagen wird. Dies erfordert sehr wenig On-Chip-Bereich, was wichtig ist, da Sie wahrscheinlich mehrere Blöcke parallel decodieren möchten und daher mehrere Kopien der Decodierungshardware benötigen.

Im Gegensatz dazu erfordern DCT-basierte Formate wie JPEG eine nicht unerhebliche Menge an Mathematik pro Pixel, ganz zu schweigen von einem komplexen Datenfluss, der verschiedene Zwischenwerte zwischen Pixeln innerhalb eines Blocks austauscht und überträgt. (In diesem Artikel finden Sie einige der wichtigsten Details der DCT-Dekodierung.) Dies würde die Hardwareimplementierung erheblich erschweren. Vermutlich hat AFAICT, keine GPU-Hardware, jemals eine DCT- oder Wavelet-basierte Texturkomprimierung implementiert .


ausgezeichnete Antwort. Sie können auch hinzufügen, dass es einige Artikel gibt, in denen erwähnt wird, dass Sie in bestimmten Situationen die Komprimierung selbst durchführen und mit Client-Code in einem Pixel-Shader dekodieren können, anstatt von dedizierter Hardware abhängig zu sein. Ich kenne keinen realen Gebrauch davon, der vielleicht nur für die Forschung wert ist, aber er existiert.
v.oddou

1
@ Nathan-Reed re transform-based compression, tatsächlich verwendete Microsofts Talisman-Projekt ein Komprimierungsschema namens TREC, das (als einer der Modi) DCT verwendete, aber im Gegensatz zu JPEG den wahlfreien Zugriff auf Blöcke ermöglichte (ich vermute, dass es eine Tabelle gegeben hat, die enthält) Adressen). Dies würde dann Daten variabler Länge für verschiedene Blöcke ermöglichen, aber die Indirektion ist für HW unangenehm - ein Grund, warum VQ TC aus der Mode gekommen ist. FWIW habe ich mit etwa einem Dutzend TC-Ideen B4 PVRTC experimentiert; Einige waren transformierungsbasiert mit fester Rate, aber "fehlende" Koeffizienten verwenden immer noch Bits. BTC-ähnliche feste Koeffizientenpositionen implizieren "freie" Informationen.
Simon F

2
@ Nathan-Reed. Nach dem, was ich gesehen habe, können alle HW-Decoder mit reinem Logikpfad (Bitdecodierung, Nachschlagen, Rechnen im Datenpfad) implementiert werden, ohne dass eine Schleife / ein Register erforderlich ist. Kennen Sie ein Schema, das die Zykluslatenz bei der Textursuche erhöht? (Ich habe zum Spaß einen VHDL-ETC1-Decoder implementiert) Ich hatte den Eindruck, dass in jede Textureinheit (TU) Decoder eingebettet waren.
Romain Piquois

30

"Wie (Hardware-) Texturkomprimierung funktioniert" ist ein großes Thema. Hoffentlich kann ich einige Einblicke geben, ohne den Inhalt von Nathans Antwort zu duplizieren .

Bedarf

Texturkomprimierung typischerweise unterscheidet sich von ‚Standard‘ Bildkomprimierungstechniken zB JPEG / PNG in vier wichtigsten Möglichkeiten, wie umrissen in Beers et al des Rendering von Compressed Textures :

  1. Dekodierungsgeschwindigkeit : Sie möchten nicht, dass die Texturkomprimierung langsamer ist (zumindest nicht merklich) als die Verwendung nicht komprimierter Texturen. Es sollte auch relativ einfach zu dekomprimieren sein, da dies dazu beitragen kann, eine schnelle Dekomprimierung ohne übermäßige Hardware- und Stromkosten zu erzielen.

  2. Direktzugriff : Sie können nicht leicht vorhersagen, welche Texel für ein bestimmtes Rendering erforderlich sind. Wenn eine Teilmenge M der Texel, auf die zugegriffen wird, beispielsweise aus der Mitte des Bildes stammt, ist es wichtig, dass Sie nicht alle 'vorherigen' Zeilen der Textur dekodieren müssen, um M zu bestimmen . Bei JPEG und PNG ist dies erforderlich, da die Pixeldekodierung von den zuvor dekodierten Daten abhängt.
    Beachten Sie, dass dies nicht bedeutet, dass Sie, nur weil Sie "zufälligen" Zugriff haben, versuchen sollten, ganz willkürlich zu sampeln

  3. Kompressionsrate und visuelle Qualität : Beers et al. Argumentieren (überzeugend), dass ein gewisser Qualitätsverlust im komprimierten Ergebnis zur Verbesserung der Kompressionsrate ein lohnender Kompromiss ist. Beim 3D-Rendering werden die Daten wahrscheinlich manipuliert (z. B. gefiltert und schattiert usw.), sodass ein gewisser Qualitätsverlust möglicherweise ausgeblendet wird.

  4. Asymmetrische Codierung / Decodierung : Obwohl sie vielleicht etwas umstrittener sind, argumentieren sie, dass es akzeptabel ist, dass der Codierungsprozess viel langsamer ist als die Decodierung. Da die Dekodierung mit HW-Füllraten erfolgen muss, ist dies im Allgemeinen akzeptabel. (Ich gebe zu, dass die Komprimierung von PVRTC, ETC2 und einigen anderen bei maximaler Qualität schneller sein könnte.)

Frühgeschichte & Techniken

Es mag einige überraschen, zu erfahren, dass es die Texturkomprimierung seit über drei Jahrzehnten gibt. Flugsimulatoren aus den 70er und 80er Jahren benötigten Zugriff auf relativ große Mengen an Texturdaten. Da 1980 1 MB RAM> 6000 USD kostete , war die Reduzierung des Textur-Footprints unerlässlich. Als weiteres Beispiel könnte Mitte der 70er Jahre bereits eine geringe Menge an Hochgeschwindigkeitsspeicher und -logik (z. B. ausreichend für einen bescheidenen 512x512-RGB-Frame-Puffer ) den Preis eines kleinen Hauses senken .

Obwohl AFAIK, nicht ausdrücklich als Texturkomprimierung bezeichnet, finden Sie in der Literatur und in Patenten Hinweise auf Techniken, einschließlich:
a. einfache Formen der mathematischen / prozeduralen Textur-Synthese,
b. Verwendung einer Einzelkanaltextur (z. B. 4bpp), die dann mit einem Pro-Textur-RGB-Wert multipliziert wird,
c. YUV und
d. Paletten (die Literatur, die die Verwendung von Heckberts Ansatz für die Komprimierung vorschlägt )

Modellierung von Bilddaten

Wie oben erwähnt, ist die Texturkomprimierung fast immer verlustbehaftet und daher besteht das Problem darin, zu versuchen, die wichtigen Daten auf kompakte Weise darzustellen, während die weniger wichtigen Informationen entsorgt werden. Die verschiedenen Schemata, die nachfolgend beschrieben werden, haben alle ein implizites "parametrisiertes" Modell, das das typische Verhalten von Texturdaten und der Reaktion des Auges approximiert.

Da die Texturkomprimierung dazu neigt, eine Codierung mit fester Rate zu verwenden, umfasst der Komprimierungsprozess üblicherweise einen Suchschritt zum Finden des Parametersatzes, der, wenn er in das Modell eingegeben wird, eine gute Annäherung an die ursprüngliche Textur erzeugt. Dieser Suchschritt kann jedoch zeitaufwändig sein.
(Mit der möglichen Ausnahme von Werkzeugen wie optipng ist dies ein weiterer Bereich, in dem sich die typische Verwendung von PNG und JPEG von Texturkomprimierungsschemata unterscheidet.)

Bevor Sie fortfahren, sollten Sie sich zum besseren Verständnis der TC mit der Hauptkomponentenanalyse (Principal Component Analysis, PCA) befassen - einem sehr nützlichen mathematischen Werkzeug für die Datenkomprimierung.

Beispiel Textur

Zum Vergleichen der verschiedenen Methoden verwenden wir das folgende Bild:

kleines lorikeet + text
Beachten Sie, dass dies ein ziemlich schwieriges Bild ist, insbesondere für Paletten- und VQTC-Methoden, da es einen Großteil des RGB-Farbwürfels abdeckt und nur 15% der Texel wiederholte Farben verwenden.

Komprimierung von PC- und Konsolentexturen (nach Mitte der 90er Jahre)

Um die Datenkosten zu senken, verwendeten einige PC-Spiele und frühe Spielekonsolen auch Palettenbilder, eine Form der Vektorquantisierung (VQ). Palettenbasierte Ansätze gehen davon aus, dass ein bestimmtes Bild nur relativ kleine Teile des RGB (A) -Farbwürfels verwendet. Ein Problem bei Palettentexturen ist, dass die Komprimierungsraten für die erreichte Qualität im Allgemeinen eher gering sind. Die Beispieltextur, die mit GIMP auf "4bpp" komprimiert wurde, hat wieder zur Folge, dass dies ein relativ schwieriges Bild für VQ-Schemata ist.
Bildbeschreibung hier eingeben

VQ mit größeren Vektoren (zB 2bpp ARGB)

Inspiriert von Beers et al. Verwendete die Dreamcast-Konsole VQ, um 2x2- oder sogar 2x4-Pixelblöcke mit einzelnen Bytes zu codieren. Während die "Vektoren" in den Palettentexturen 3- oder 4-dimensional sind, können die 2x2-Pixelblöcke als 16-dimensional betrachtet werden. Das Komprimierungsschema geht davon aus, dass es eine ausreichende ungefähre Wiederholung dieser Vektoren gibt.

Obwohl VQ mit ~ 2bpp eine zufriedenstellende Qualität erzielen kann, besteht das Problem bei diesen Schemata darin, dass abhängige Speicherlesevorgänge erforderlich sind: Auf ein anfängliches Lesen aus der Indexkarte zum Bestimmen des Codes für das Pixel folgt eine Sekunde, um die zugeordneten Pixeldaten tatsächlich abzurufen mit diesem Code. Zusätzliche Caches können helfen, einen Teil der auftretenden Latenz zu verringern, erhöhen jedoch die Komplexität der Hardware.

Das mit dem 2bpp Dreamcast-Schema komprimierte Beispielbild ist 2bpp VQ Ergebnis. Die Indexkarte ist:2bpp VQ-Indexkarte

Die Komprimierung von VQ-Daten kann auf verschiedene Arten erfolgen, IIRC , wobei PCA verwendet wurde, um die 16D-Vektoren entlang des Hauptvektors in 2 Sätze abzuleiten und dann zu partitionieren, so dass zwei repräsentative Vektoren den mittleren quadratischen Fehler minimierten. Der Prozess wurde dann wiederholt, bis 256 Kandidatenvektoren erzeugt wurden. Anschließend wurde ein globaler k-means / Lloyd-Algorithmus- Ansatz angewendet, um die Repräsentanten zu verbessern.

Farbraum-Transformationen

Farbraumtransformationen nutzen auch PCA, wobei festgestellt wird, dass die globale Verteilung von Farben häufig entlang einer Hauptachse mit weitaus geringerer Verteilung entlang der anderen Achsen verteilt ist. Bei YUV-Darstellungen wird davon ausgegangen, dass a) die Hauptachse häufig in der Luma-Richtung liegt und b) das Auge empfindlicher auf Änderungen in dieser Richtung reagiert.

Das 3dfx Voodoo-System lieferte "YAB" , ein 8-Bit- "Narrow Channel" -Komprimierungssystem, das jedes 8-Bit-Texel in ein 322-Format aufteilte und eine vom Benutzer ausgewählte Farbtransformation auf diese Daten anwendete, um sie in RGB abzubilden. Die Hauptachse hatte somit 8 Ebenen und die kleineren Achsen jeweils 4 Ebenen.

Der S3 Virge-Chip verfügte über ein etwas einfacheres 4-Bit-Schema, mit dem der Benutzer für die gesamte Textur zwei Endfarben festlegen konnte , die auf der Hauptachse liegen sollten, zusammen mit einer 4-Bit-Monochrom-Textur. Der Wert pro Pixel mischt dann die Endfarben mit den entsprechenden Gewichten, um das RGB-Ergebnis zu erhalten.

BTC-basierte Systeme

Delp und Mitchell haben einige Jahre zurückgespult und ein einfaches (monochromes) Bildkomprimierungsschema namens Block Truncation Coding (BTC) entworfen. . Dieses Papier enthielt auch einen Komprimierungsalgorithmus, aber für unsere Zwecke interessieren uns hauptsächlich die resultierenden komprimierten Daten und der Dekomprimierungsprozess.

Bei diesem Schema werden Bilder in der Regel in 4 × 4-Pixelblöcke aufgeteilt, die unabhängig mit einem lokalisierten VQ-Algorithmus komprimiert werden können. Jeder Block wird durch zwei "Werte" a und b und einen 4 × 4-Satz von Indexbits dargestellt, die angeben, welcher der beiden Werte für jedes Pixel verwendet werden soll.

S3TC : 4bpp RGB (+ 1 - Bit - alpha)
Obwohl mehrere Farbvarianten von BTC für die Bildkompression wurden vorgeschlagen, für uns von Interesse ist Iourcha et al die S3TC , von denen einige eine Wiederentdeckung der etwas in Vergessenheit geratene Werk zu sein scheint Hoffert et al , dass wurde in Apples Quicktime verwendet.

Der ursprüngliche S3TC ohne die DirectX-Varianten komprimiert Blöcke mit RGB oder RGB + 1-Bit-Alpha auf 4 bpp. Jeder 4x4-Block in der Textur wird durch zwei Endfarben A und B ersetzt , von denen bis zu zwei andere Farben durch lineare Mischungen mit festem Gewicht abgeleitet werden. Außerdem hat jedes Texel im Block einen 2-Bit-Index, der festlegt, wie eine dieser vier Farben ausgewählt werden soll.

Das folgende Beispiel zeigt einen 4x4-Pixel-Ausschnitt des mit dem AMD / ATI Compressenator-Tool komprimierten Testbilds. ( Technisch gesehen stammt es aus einer 512x512-Version des Test-Images, aber ich habe keine Zeit, um die Beispiele zu aktualisieren .) Dies veranschaulicht den Kompressionsprozess: Der Durchschnitt und die Hauptachse der Farben werden berechnet. Anschließend wird eine optimale Anpassung durchgeführt, um zwei Endpunkte zu finden, die auf der Achse liegen, und zwar zusammen mit den beiden abgeleiteten 1: 2- und 2: 1-Überblendungen (oder in einigen Fällen einer 50: 50-Überblendung) dieser Endpunkte minimiert den Fehler. Jedes Originalpixel wird dann auf eine dieser Farben abgebildet, um das Ergebnis zu erzielen.
Bildbeschreibung hier eingeben

Wenn, wie in diesem Fall, die Farben durch die Hauptachse vernünftig angenähert werden, ist der Fehler relativ gering. Wenn jedoch, wie im unten gezeigten benachbarten 4x4-Block, die Farben vielfältiger sind, ist der Fehler höher.
Bildbeschreibung hier eingeben

Das mit dem AMD Compressonator komprimierte Beispielbild erzeugt:
Bildbeschreibung hier eingeben

Da die Farben blockweise unabhängig voneinander bestimmt werden, kann es an den Blockgrenzen zu Diskontinuitäten kommen. Solange die Auflösung jedoch hoch genug ist, können diese Blockartefakte unbemerkt bleiben:
Bildbeschreibung hier eingeben

ETC1 : 4bpp RGB
Ericsson Texture Compression funktioniert auch mit 4x4 Texelblöcken, geht jedoch davon aus, dass die Hauptachse einer lokalen Texelmenge ähnlich wie bei YUV häufig sehr stark mit "Luma" korreliert. Der Texelsatz kann dann nur durch eine durchschnittliche Farbe und eine hoch quantisierte, skalare "Länge" der Projektion der Texels auf diese angenommene Achse dargestellt werden.

Da dies die Datenspeicherkosten im Vergleich zu S3TC verringert, ermöglicht es ETC, ein Partitionsschema einzuführen, bei dem der 4x4-Block in ein Paar horizontaler 4x2- oder vertikaler 2x4-Unterblöcke unterteilt wird. Diese haben jeweils ihre eigene Durchschnittsfarbe. Das Beispielbild zeigt: Der Bereich um den Schnabel zeigt auch die horizontale und vertikale Unterteilung der 4x4-Blöcke.
Bildbeschreibung hier eingeben
Bildbeschreibung hier eingeben

Global + Lokal

Es gibt einige Texturkomprimierungssysteme, bei denen es sich um eine Kreuzung zwischen globalen und lokalen Schemata handelt, z. B. die verteilten Paletten von Ivanov und Kuzmin oder die Methode von PVRTC .

PVRTC : 4 & 2 bpp RGBA
PVRTC geht davon aus, dass ein (in der Praxis bilinear) hochskaliertes Bild eine gute Annäherung an das Ziel mit voller Auflösung darstellt und dass der Unterschied zwischen der Annäherung und dem Ziel, dh dem Delta-Bild, lokal monochromatisch ist, d. H hat eine dominante Hauptachse. Ferner wird davon ausgegangen, dass die lokale Hauptachse über das Bild interpoliert werden kann.

(zu tun: Hinzufügen von Bildern mit Aufschlüsselung)

Die mit PVRTC1 4bpp komprimierte Beispieltextur erzeugt: mit dem Bereich um den Schnabel: Im Vergleich zu BTC-Schemata werden die Blockartefakte normalerweise eliminiert, aber es kann manchmal zu einem "Überschwingen" kommen, wenn beispielsweise starke Diskontinuitäten im Quellbild auftreten die Silhouette des Kopfes des Lorikeet.
Bildbeschreibung hier eingeben

Bildbeschreibung hier eingeben

Die 2bpp-Variante hat natürlich einen höheren Fehler als die 4bpp-Variante (man beachte den Präzisionsverlust um die blauen, hochfrequenten Bereiche in der Nähe des Halses), ist aber wohl immer noch von angemessener Qualität:
Bildbeschreibung hier eingeben

Ein Hinweis zu den Dekomprimierungskosten

Obwohl die Komprimierungsalgorithmen für die oben beschriebenen Schemata moderate bis hohe Bewertungskosten aufweisen, sind die Dekomprimierungsalgorithmen, insbesondere für Hardware-Implementierungen, relativ kostengünstig. ETC1 benötigt zum Beispiel wenig mehr als ein paar Multiplexer und Addierer mit geringer Genauigkeit. S3TC effektiv etwas mehr Additionseinheiten, um das Mischen durchzuführen; und PVRTC wieder etwas mehr. Theoretisch könnten diese einfachen TC-Schemata es einer GPU-Architektur ermöglichen, eine Dekomprimierung erst unmittelbar vor der Filterungsphase zu vermeiden, wodurch die Wirksamkeit der internen Caches maximiert wird.

Andere Schemata

Andere gebräuchliche TC-Modi, die erwähnt werden sollten, sind:

  • ETC2 - ist eine (4bpp) Obermenge von ETC1, die das Handling von Regionen mit Farbverteilungen verbessert, die nicht gut mit 'Luma' übereinstimmen. Es gibt auch eine 4-Bit-Variante, die 1-Bit-Alpha unterstützt, und ein 8-Bit-Format für RGBA.

  • ATC - Ist effektiv eine kleine Variation von S3TC .

  • FXT1 (3dfx) war eine ehrgeizigere Variante des S3TC-Themas .

  • BC6 & BC7: Ein blockbasiertes 8-Bit-System, das ARGB unterstützt. Abgesehen von den HDR-Modi verwenden diese ein komplexeres Partitionierungssystem als ETC, um eine bessere Modellierung der Bildfarbverteilung zu erreichen.

  • PVRTC2: 2 & 4bpp ARGB. Dies führt zusätzliche Modi ein, einschließlich eines, um Einschränkungen mit starken Grenzen in den Bildern zu überwinden.

  • ASTC: Dies ist ebenfalls ein blockbasiertes System, das jedoch insofern etwas komplizierter ist, als es eine große Anzahl möglicher Blockgrößen aufweist, die auf einen weiten Bereich von bpp abzielen. Es enthält auch Funktionen wie bis zu 4 Partitionsbereiche mit einem Pseudozufalls-Partitionsgenerator und eine variable Auflösung für die Indexdaten und / oder die Farbgenauigkeit und die Farbmodelle.


1
Wow, das sollte irgendwo ein Blogpost sein! Gute Antwort!
Glampert

2
Ich bin froh, dass es hilfreich ist. Was einen Blog betrifft, habe ich diesen vor einem Jahrzehnt geschrieben, aber ich habe wirklich keine Zeit, sie zu machen.
Simon F
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.