Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(88)

Side by Side Diff: third_party/ktx/ktx.cpp

Issue 302333002: Initial KTX file decoder (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: More code comments Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/ktx/ktx.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1
2 /*
3 * Copyright 2014 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9 #include "ktx.h"
10 #include "SkStream.h"
11 #include "SkEndian.h"
12
13 #include "gl/GrGLDefines.h"
14
15 #define KTX_FILE_IDENTIFIER_SIZE 12
16 static const uint8_t KTX_FILE_IDENTIFIER[KTX_FILE_IDENTIFIER_SIZE] = {
17 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
18 };
19
20 static const uint32_t kKTX_ENDIANNESS_CODE = 0x04030201;
21
22 bool SkKTXFile::KeyValue::readKeyAndValue(const uint8_t* data) {
23 const char *key = reinterpret_cast<const char *>(data);
24 const char *value = key;
25
26 size_t bytesRead = 0;
27 while (*value != '\0' && bytesRead < this->fDataSz) {
28 ++bytesRead;
29 ++value;
30 }
31
32 // Error of some sort..
33 if (bytesRead >= this->fDataSz) {
34 return false;
35 }
36
37 // Read the zero terminator
38 ++bytesRead;
39 ++value;
40
41 size_t bytesLeft = this->fDataSz - bytesRead;
42 this->fKey.set(key, bytesRead);
43 if (bytesLeft > 0) {
44 this->fValue.set(value, bytesLeft);
45 } else {
46 return false;
47 }
48
49 return true;
50 }
51
52 uint32_t SkKTXFile::readInt(const uint8_t** buf, size_t* bytesLeft) const {
53 SkASSERT(NULL != buf && NULL != bytesLeft);
54
55 uint32_t result;
56
57 if (*bytesLeft < 4) {
58 SkASSERT(false);
59 return 0;
60 }
61
62 memcpy(&result, *buf, 4);
63 *buf += 4;
64
65 if (fSwapBytes) {
66 SkEndianSwap32(result);
67 }
68
69 *bytesLeft -= 4;
70
71 return result;
72 }
73
74 bool SkKTXFile::isETC1() const {
75 return this->valid() && GR_GL_COMPRESSED_RGB8_ETC1 == fHeader.fGLInternalFor mat;
76 }
77
78 bool SkKTXFile::isRGBA8() const {
79 return this->valid() && GR_GL_RGBA8 == fHeader.fGLInternalFormat;
80 }
81
82 bool SkKTXFile::isRGB8() const {
83 return this->valid() && GR_GL_RGB8 == fHeader.fGLInternalFormat;
84 }
85
86 bool SkKTXFile::readKTXFile(const uint8_t* data, size_t dataLen) {
87 const uint8_t *buf = data;
88 size_t bytesLeft = dataLen;
89
90 // Make sure original KTX header is there... this should have been checked
91 // already by a call to is_ktx()
92 SkASSERT(bytesLeft > KTX_FILE_IDENTIFIER_SIZE);
93 SkASSERT(0 == memcmp(KTX_FILE_IDENTIFIER, buf, KTX_FILE_IDENTIFIER_SIZE));
94 buf += KTX_FILE_IDENTIFIER_SIZE;
95 bytesLeft -= KTX_FILE_IDENTIFIER_SIZE;
96
97 // Read header, but first make sure that we have the proper space: we need
98 // two 32-bit ints: 1 for endianness, and another for the mandatory image
99 // size after the header.
100 if (bytesLeft < 8 + sizeof(Header)) {
101 return false;
102 }
103
104 uint32_t endianness = this->readInt(&buf, &bytesLeft);
105 fSwapBytes = kKTX_ENDIANNESS_CODE != endianness;
106
107 // Read header values
108 fHeader.fGLType = this->readInt(&buf, &bytesLeft);
109 fHeader.fGLTypeSize = this->readInt(&buf, &bytesLeft);
110 fHeader.fGLFormat = this->readInt(&buf, &bytesLeft);
111 fHeader.fGLInternalFormat = this->readInt(&buf, &bytesLeft);
112 fHeader.fGLBaseInternalFormat = this->readInt(&buf, &bytesLeft);
113 fHeader.fPixelWidth = this->readInt(&buf, &bytesLeft);
114 fHeader.fPixelHeight = this->readInt(&buf, &bytesLeft);
115 fHeader.fPixelDepth = this->readInt(&buf, &bytesLeft);
116 fHeader.fNumberOfArrayElements = this->readInt(&buf, &bytesLeft);
117 fHeader.fNumberOfFaces = this->readInt(&buf, &bytesLeft);
118 fHeader.fNumberOfMipmapLevels = this->readInt(&buf, &bytesLeft);
119 fHeader.fBytesOfKeyValueData = this->readInt(&buf, &bytesLeft);
120
121 // Check for things that we understand...
122 {
123 // First, we only support compressed formats and single byte
124 // representations at the moment. If the internal format is
125 // compressed, the the GLType field in the header must be zero.
126 // In the future, we may support additional data types (such
127 // as GL_UNSIGNED_SHORT_5_6_5)
128 if (fHeader.fGLType != 0 && fHeader.fGLType != GR_GL_UNSIGNED_BYTE) {
129 return false;
130 }
131
132 // This means that for well-formatted KTX files, the glTypeSize
133 // field must be one...
134 if (fHeader.fGLTypeSize != 1) {
135 return false;
136 }
137
138 // We don't support 3D textures.
139 if (fHeader.fPixelDepth > 1) {
140 return false;
141 }
142
143 // We don't support texture arrays
144 if (fHeader.fNumberOfArrayElements > 1) {
145 return false;
146 }
147
148 // We don't support cube maps
149 if (fHeader.fNumberOfFaces > 1) {
150 return false;
151 }
152 }
153
154 // Make sure that we have enough bytes left for the key/value
155 // data according to what was said in the header.
156 if (bytesLeft < fHeader.fBytesOfKeyValueData) {
157 return false;
158 }
159
160 // Next read the key value pairs
161 size_t keyValueBytesRead = 0;
162 while (keyValueBytesRead < fHeader.fBytesOfKeyValueData) {
163 uint32_t keyValueBytes = this->readInt(&buf, &bytesLeft);
164 keyValueBytesRead += 4;
165
166 if (keyValueBytes > bytesLeft) {
167 return false;
168 }
169
170 KeyValue kv(keyValueBytes);
171 if (!kv.readKeyAndValue(buf)) {
172 return false;
173 }
174
175 fKeyValuePairs.push_back(kv);
176
177 uint32_t keyValueBytesPadded = (keyValueBytes + 3) & ~3;
178 buf += keyValueBytesPadded;
179 keyValueBytesRead += keyValueBytesPadded;
180 bytesLeft -= keyValueBytesPadded;
181 }
182
183 // Read the pixel data...
184 int mipmaps = SkMax32(fHeader.fNumberOfMipmapLevels, 1);
185 SkASSERT(mipmaps == 1);
186
187 int arrayElements = SkMax32(fHeader.fNumberOfArrayElements, 1);
188 SkASSERT(arrayElements == 1);
189
190 int faces = SkMax32(fHeader.fNumberOfFaces, 1);
191 SkASSERT(faces == 1);
192
193 int depth = SkMax32(fHeader.fPixelDepth, 1);
194 SkASSERT(depth == 1);
195
196 for (int mipmap = 0; mipmap < mipmaps; ++mipmap) {
197 // Make sure that we have at least 4 more bytes for the first image size
198 if (bytesLeft < 4) {
199 return false;
200 }
201
202 uint32_t imgSize = this->readInt(&buf, &bytesLeft);
203
204 // Truncated file.
205 if (bytesLeft < imgSize) {
206 return false;
207 }
208
209 // !FIXME! If support is ever added for cube maps then the padding
210 // needs to be taken into account here.
211 for (int arrayElement = 0; arrayElement < arrayElements; ++arrayElement) {
212 for (int face = 0; face < faces; ++face) {
213 for (int z = 0; z < depth; ++z) {
214 PixelData pd(buf, imgSize);
215 fPixelData.append(1, &pd);
216 }
217 }
218 }
219
220 uint32_t imgSizePadded = (imgSize + 3) & ~3;
221 buf += imgSizePadded;
222 bytesLeft -= imgSizePadded;
223 }
224
225 return bytesLeft == 0;
226 }
227
228 bool SkKTXFile::is_ktx(const uint8_t *data) {
229 return 0 == memcmp(KTX_FILE_IDENTIFIER, data, KTX_FILE_IDENTIFIER_SIZE);
230 }
231
232 bool SkKTXFile::is_ktx(SkStreamRewindable* stream) {
233 // Read the KTX header and make sure it's valid.
234 unsigned char buf[KTX_FILE_IDENTIFIER_SIZE];
235 bool largeEnough =
236 stream->read((void*)buf, KTX_FILE_IDENTIFIER_SIZE) == KTX_FILE_IDENTIFIE R_SIZE;
237 stream->rewind();
238 if (!largeEnough) {
239 return false;
240 }
241 return is_ktx(buf);
242 }
OLDNEW
« no previous file with comments | « third_party/ktx/ktx.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698