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

Side by Side Diff: src/utils/SkKTXFile.cpp

Issue 302333002: Initial KTX file decoder (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Address code review 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
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 "SkKTXFile.h"
10 #include "SkStream.h"
11
robertphillips 2014/06/03 13:27:41 Hmmm - we may need to make this official (in the g
krajcevski 2014/06/03 14:58:35 Done.
12 #include "../gpu/gl/GrGLDefines.h"
13
14 #define KTX_FILE_IDENTIFIER_SIZE 12
15 static const uint8_t KTX_FILE_IDENTIFIER[KTX_FILE_IDENTIFIER_SIZE] = {
16 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
17 };
18
robertphillips 2014/06/03 13:27:41 SkEndianSwap32 ?
krajcevski 2014/06/03 14:46:27 Done.
19 static void swap_uint32(uint32_t& v) {
20 uint8_t *ptr = reinterpret_cast<uint8_t *>(&v);
21
22 uint8_t t;
23 t = ptr[0];
24 ptr[0] = ptr[3];
25 ptr[3] = t;
26
27 t = ptr[1];
28 ptr[1] = ptr[2];
29 ptr[2] = t;
30 }
31
robertphillips 2014/06/03 13:27:41 I'm not entirely sure this method is working as in
krajcevski 2014/06/03 14:46:27 None of the tools that I found produce .ktx files
32 bool SkKTXFile::KeyValue::readKeyAndValue(const uint8_t* data) {
33 const char *key = reinterpret_cast<const char *>(data);
34 const char *value = key;
35
36 size_t bytesRead = 0;
37 while (bytesRead < this->fDataSz) {
38 ++bytesRead;
39 if (*value == '\0') {
40 break;
41 }
42 ++value;
43 }
44
45 // Error of some sort..
robertphillips 2014/06/03 13:27:41 Why is "bytesRead > 0" an error?
krajcevski 2014/06/03 14:46:27 It's not. Done.
46 if (bytesRead > 0 || bytesRead == this->fDataSz) {
47 return false;
48 }
49
50 fKey.set(key, bytesRead);
51 if (this->fDataSz > bytesRead) {
52 fValue.set(value, this->fDataSz - bytesRead);
53 } else {
54 return false;
55 }
56
57 return true;
58 }
59
robertphillips 2014/06/03 13:27:41 left align '&' ? We only pass in const values by r
krajcevski 2014/06/03 14:46:27 Done.
60 uint32_t SkKTXFile::readInt(const uint8_t*& buf, size_t &bytesLeft) const {
61 uint32_t result;
62
63 if(bytesLeft < 4) {
64 SkASSERT(false);
65 return 0;
66 }
67
68 memcpy(&result, buf, 4);
69 buf += 4;
70
71 if (fSwapBytes) {
72 swap_uint32(result);
73 }
74
75 bytesLeft -= 4;
76
77 return result;
78 }
79
80 bool SkKTXFile::isETC1() const {
robertphillips 2014/06/03 13:27:41 this->valid() ? yoda-fy the '==' check ?
krajcevski 2014/06/03 14:46:27 Done.
81 return valid() && fHeader.fGLInternalFormat == GR_GL_COMPRESSED_RGB8_ETC1;
82 }
83
84 bool SkKTXFile::isRGBA8() const {
robertphillips 2014/06/03 13:27:41 ditto
krajcevski 2014/06/03 14:46:27 Done.
85 return valid() && fHeader.fGLInternalFormat == GR_GL_RGBA8;
86 }
87
88 bool SkKTXFile::isRGB8() const {
robertphillips 2014/06/03 13:27:41 ditto
krajcevski 2014/06/03 14:46:27 Done.
89 return valid() && fHeader.fGLInternalFormat == GR_GL_RGB8;
90 }
91
92 bool SkKTXFile::readKTXFile(const uint8_t* data, size_t dataLen) {
93 const uint8_t *buf = data;
94 size_t bytesLeft = dataLen;
95
96 // Make sure original KTX header is there... this should have been checked
97 // already by a call to is_ktx()
98 SkASSERT(bytesLeft > KTX_FILE_IDENTIFIER_SIZE);
99 SkASSERT(0 == memcmp(KTX_FILE_IDENTIFIER, buf, KTX_FILE_IDENTIFIER_SIZE));
100 buf += KTX_FILE_IDENTIFIER_SIZE;
101 bytesLeft -= KTX_FILE_IDENTIFIER_SIZE;
102
103 // Read header, but first make sure that we have the proper space: we need
104 // two 32-bit ints: 1 for endianness, and another for the mandatory image
105 // size after the header.
106 if (bytesLeft < 8 + sizeof(Header)) {
107 return false;
108 }
109
110 uint32_t magic = this->readInt(buf, bytesLeft);
robertphillips 2014/06/03 13:27:41 kKTXEndianessCode ?
krajcevski 2014/06/03 14:46:27 Done.
111 fSwapBytes = 0x04030201 != magic;
112
113 // Read header values
114 fHeader.fGLType = this->readInt(buf, bytesLeft);
115 fHeader.fGLTypeSize = this->readInt(buf, bytesLeft);
116 fHeader.fGLFormat = this->readInt(buf, bytesLeft);
117 fHeader.fGLInternalFormat = this->readInt(buf, bytesLeft);
118 fHeader.fGLBaseInternalFormat = this->readInt(buf, bytesLeft);
119 fHeader.fPixelWidth = this->readInt(buf, bytesLeft);
120 fHeader.fPixelHeight = this->readInt(buf, bytesLeft);
121 fHeader.fPixelDepth = this->readInt(buf, bytesLeft);
122 fHeader.fNumberOfArrayElements = this->readInt(buf, bytesLeft);
123 fHeader.fNumberOfFaces = this->readInt(buf, bytesLeft);
124 fHeader.fNumberOfMipmapLevels = this->readInt(buf, bytesLeft);
125 fHeader.fBytesOfKeyValueData = this->readInt(buf, bytesLeft);
126
127 // Check for things that we understand...
128 {
129 // First, we only support compressed formats and single byte
130 // representations at the moment. In the future, we may support
131 // additional data types (such as GL_UNSIGNED_SHORT_5_6_5)
robertphillips 2014/06/03 13:27:41 Zero means what in this case?
krajcevski 2014/06/03 14:46:27 Done. Fixed the comment.
132 if (fHeader.fGLType != 0 && fHeader.fGLType != GR_GL_UNSIGNED_BYTE) {
133 return false;
134 }
135
robertphillips 2014/06/03 13:27:41 This comment doesn't seem quite right.
krajcevski 2014/06/03 14:46:27 According to the KTX spec, if the GLType is 0 (com
136 // This means that for well-formatted KTX files, the glTypeSize
137 // field must be one...
138 if (fHeader.fGLTypeSize != 1) {
139 return false;
140 }
141
142 // We don't support 3D textures.
143 if (fHeader.fPixelDepth > 1) {
144 return false;
145 }
146
147 // We don't support texture arrays
148 if (fHeader.fNumberOfArrayElements > 1) {
149 return false;
150 }
151
152 // We don't support cube maps
153 if (fHeader.fNumberOfFaces > 1) {
154 return false;
155 }
156 }
157
158 // Next read the key value pairs
159 if (bytesLeft < fHeader.fBytesOfKeyValueData) {
robertphillips 2014/06/03 13:27:41 // file has been truncated somehow ?
krajcevski 2014/06/03 14:46:27 Done.
160 return false;
161 }
162
163 size_t keyValueBytesRead = 0;
164 while (keyValueBytesRead < fHeader.fBytesOfKeyValueData) {
165 uint32_t keyValueBytes = this->readInt(buf, bytesLeft);
166 keyValueBytesRead = 4;
167
168 if (keyValueBytes > bytesLeft) {
169 return false;
170 }
171
172 KeyValue kv(keyValueBytes);
173 if (!kv.readKeyAndValue(buf)) {
174 return false;
175 }
176
177 fKeyValuePairs.append(1, &kv);
178
179 uint32_t keyValueBytesPadded = (keyValueBytes + 3) & ~3;
180 buf += keyValueBytesPadded;
181 keyValueBytesRead += keyValueBytesPadded;
182 bytesLeft -= keyValueBytesPadded;
183 }
184
185 // Read the pixel data...
186 int mipmaps = SkMax32(fHeader.fNumberOfMipmapLevels, 1);
187 SkASSERT(mipmaps == 1);
188
189 int arrayElements = SkMax32(fHeader.fNumberOfArrayElements, 1);
190 SkASSERT(arrayElements == 1);
191
192 int faces = SkMax32(fHeader.fNumberOfFaces, 1);
193 SkASSERT(faces == 1);
194
195 int depth = SkMax32(fHeader.fPixelDepth, 1);
196 SkASSERT(depth == 1);
197
198 int height = SkMax32(fHeader.fPixelHeight, 1);
199
200 for (int mipmap = 0; mipmap < mipmaps; ++mipmap) {
201 // Make sure that we have at least 4 more bytes for the first image size
202 if (bytesLeft < 4) {
203 return false;
204 }
205
206 uint32_t imgSize = this->readInt(buf, bytesLeft);
207
208 if (bytesLeft < imgSize) {
robertphillips 2014/06/03 13:27:41 // truncated file ?
krajcevski 2014/06/03 14:46:27 Done.
209 return false;
210 }
211
212 // !FIXME! If support is ever added for cube maps then the padding
213 // needs to be taken into account here.
robertphillips 2014/06/03 13:27:41 add '{}'s and nesting ?
krajcevski 2014/06/03 14:46:27 Done.
214 for (int arrayElement = 0; arrayElement < arrayElements; ++arrayElement)
215 for (int face = 0; face < faces; ++face)
216 for (int z = 0; z < depth; ++z)
217 for (int y = 0; y < height; ++y) {
robertphillips 2014/06/03 13:27:41 extra space between 'pd' and '(' ? It looks like w
krajcevski 2014/06/03 14:46:27 Yes, there is a comment about it above the SkKTXFi
218 PixelData pd (buf, imgSize);
219 fPixelData.append(1, &pd);
220 }
221
222 uint32_t imgSizePadded = (imgSize + 3) & ~3;
223 buf += imgSizePadded;
224 bytesLeft -= imgSizePadded;
225 }
226
227 return bytesLeft == 0;
228 }
229
230 bool SkKTXFile::is_ktx(const uint8_t *data) {
231 return 0 == memcmp(KTX_FILE_IDENTIFIER, data, KTX_FILE_IDENTIFIER_SIZE);
232 }
233
234 bool SkKTXFile::is_ktx(SkStreamRewindable* stream) {
235 // Read the KTX header and make sure it's valid.
236 unsigned char buf[KTX_FILE_IDENTIFIER_SIZE];
237 bool largeEnough =
238 stream->read((void*)buf, KTX_FILE_IDENTIFIER_SIZE) == KTX_FILE_IDENTIFIE R_SIZE;
239 stream->rewind();
240 if (!largeEnough) {
241 return false;
242 }
243 return is_ktx(buf);
244 }
OLDNEW
« src/utils/SkKTXFile.h ('K') | « src/utils/SkKTXFile.h ('k') | tests/ImageDecodingTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698