OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2009 Apple Inc. All rights reserved. | 2 * Copyright (C) 2009 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 19 matching lines...) Expand all Loading... |
30 namespace blink { | 30 namespace blink { |
31 | 31 |
32 WebGLTexture* WebGLTexture::create(WebGLRenderingContextBase* ctx) | 32 WebGLTexture* WebGLTexture::create(WebGLRenderingContextBase* ctx) |
33 { | 33 { |
34 return new WebGLTexture(ctx); | 34 return new WebGLTexture(ctx); |
35 } | 35 } |
36 | 36 |
37 WebGLTexture::WebGLTexture(WebGLRenderingContextBase* ctx) | 37 WebGLTexture::WebGLTexture(WebGLRenderingContextBase* ctx) |
38 : WebGLSharedPlatform3DObject(ctx) | 38 : WebGLSharedPlatform3DObject(ctx) |
39 , m_target(0) | 39 , m_target(0) |
40 , m_isNPOT(false) | |
41 , m_isCubeComplete(false) | |
42 , m_isComplete(false) | |
43 , m_isFloatType(false) | |
44 , m_isHalfFloatType(false) | |
45 , m_isWebGL2OrHigher(ctx->isWebGL2OrHigher()) | 40 , m_isWebGL2OrHigher(ctx->isWebGL2OrHigher()) |
46 , m_immutable(false) | |
47 , m_baseLevel(0) | 41 , m_baseLevel(0) |
48 , m_maxLevel(1000) | 42 , m_maxLevel(1000) |
49 { | 43 { |
50 setObject(ctx->webContext()->createTexture()); | 44 setObject(ctx->webContext()->createTexture()); |
51 } | 45 } |
52 | 46 |
53 WebGLTexture::~WebGLTexture() | 47 WebGLTexture::~WebGLTexture() |
54 { | 48 { |
55 // See the comment in WebGLObject::detachAndDeleteObject(). | 49 // See the comment in WebGLObject::detachAndDeleteObject(). |
56 detachAndDeleteObject(); | 50 detachAndDeleteObject(); |
57 } | 51 } |
58 | 52 |
59 void WebGLTexture::setTarget(GLenum target, GLint maxLevel) | 53 void WebGLTexture::setTarget(GLenum target, GLint maxLevel) |
60 { | 54 { |
61 if (!object()) | 55 if (!object()) |
62 return; | 56 return; |
63 // Target is finalized the first time bindTexture() is called. | 57 // Target is finalized the first time bindTexture() is called. |
64 if (m_target) | 58 if (m_target) |
65 return; | 59 return; |
66 switch (target) { | 60 m_target = target; |
67 case GL_TEXTURE_2D: | |
68 case GL_TEXTURE_2D_ARRAY: | |
69 case GL_TEXTURE_3D: | |
70 m_target = target; | |
71 m_info.resize(1); | |
72 m_info[0].resize(maxLevel); | |
73 break; | |
74 case GL_TEXTURE_CUBE_MAP: | |
75 m_target = target; | |
76 m_info.resize(6); | |
77 for (int ii = 0; ii < 6; ++ii) | |
78 m_info[ii].resize(maxLevel); | |
79 break; | |
80 } | |
81 } | 61 } |
82 | 62 |
83 void WebGLTexture::setParameteri(GLenum pname, GLint param) | 63 void WebGLTexture::setParameteri(GLenum pname, GLint param) |
84 { | 64 { |
85 if (!object() || !m_target) | 65 if (!object() || !m_target) |
86 return; | 66 return; |
87 switch (pname) { | 67 switch (pname) { |
88 case GL_TEXTURE_MIN_FILTER: | 68 case GL_TEXTURE_MIN_FILTER: |
89 switch (param) { | 69 switch (param) { |
90 case GL_NEAREST: | 70 case GL_NEAREST: |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 if (m_isWebGL2OrHigher && param >= 0) | 116 if (m_isWebGL2OrHigher && param >= 0) |
137 m_baseLevel = param; | 117 m_baseLevel = param; |
138 break; | 118 break; |
139 case GL_TEXTURE_MAX_LEVEL: | 119 case GL_TEXTURE_MAX_LEVEL: |
140 if (m_isWebGL2OrHigher && param >= 0) | 120 if (m_isWebGL2OrHigher && param >= 0) |
141 m_maxLevel = param; | 121 m_maxLevel = param; |
142 break; | 122 break; |
143 default: | 123 default: |
144 return; | 124 return; |
145 } | 125 } |
146 update(); | |
147 } | 126 } |
148 | 127 |
149 void WebGLTexture::setParameterf(GLenum pname, GLfloat param) | 128 void WebGLTexture::setParameterf(GLenum pname, GLfloat param) |
150 { | 129 { |
151 if (!object() || !m_target) | 130 if (!object() || !m_target) |
152 return; | 131 return; |
153 GLint iparam = static_cast<GLint>(param); | 132 GLint iparam = static_cast<GLint>(param); |
154 setParameteri(pname, iparam); | 133 setParameteri(pname, iparam); |
155 } | 134 } |
156 | 135 |
157 void WebGLTexture::setLevelInfo(GLenum target, GLint level, GLenum internalForma
t, GLsizei width, GLsizei height, GLsizei depth, GLenum type) | |
158 { | |
159 ASSERT(!m_immutable); | |
160 | |
161 if (!object() || !m_target) | |
162 return; | |
163 // We assume level, internalFormat, width, height, depth, and type have all
been | |
164 // validated already. | |
165 int index = mapTargetToIndex(target); | |
166 if (index < 0) | |
167 return; | |
168 m_info[index][level].setInfo(internalFormat, width, height, depth, type); | |
169 update(); | |
170 } | |
171 | |
172 void WebGLTexture::setTexStorageInfo(GLenum target, GLint levels, GLenum interna
lFormat, GLsizei width, GLsizei height, GLsizei depth) | |
173 { | |
174 ASSERT(!m_immutable); | |
175 | |
176 // We assume level, internalFormat, width, height, and depth have all been | |
177 // validated already. | |
178 if (!object() || !m_target || target != m_target) | |
179 return; | |
180 | |
181 GLenum type = getValidTypeForInternalFormat(internalFormat); | |
182 if (type == GL_NONE) | |
183 return; | |
184 | |
185 for (size_t ii = 0; ii < m_info.size(); ++ii) { | |
186 GLsizei levelWidth = width; | |
187 GLsizei levelHeight = height; | |
188 GLsizei levelDepth = depth; | |
189 for (GLint level = 0; level < levels; ++level) { | |
190 LevelInfo& info = m_info[ii][level]; | |
191 info.setInfo(internalFormat, levelWidth, levelHeight, levelDepth, ty
pe); | |
192 levelWidth = std::max(1, levelWidth >> 1); | |
193 levelHeight = std::max(1, levelHeight >> 1); | |
194 levelDepth = m_target == GL_TEXTURE_2D_ARRAY ? levelDepth : std::max
(1, levelDepth >> 1); | |
195 } | |
196 } | |
197 update(); | |
198 | |
199 m_immutable = true; | |
200 } | |
201 | |
202 void WebGLTexture::generateMipmapLevelInfo() | |
203 { | |
204 if (!object() || !m_target) | |
205 return; | |
206 if (!canGenerateMipmaps()) | |
207 return; | |
208 if (!m_isComplete) { | |
209 for (size_t ii = 0; ii < m_info.size(); ++ii) { | |
210 const LevelInfo& info0 = m_info[ii][m_baseLevel]; | |
211 GLsizei width = info0.width; | |
212 GLsizei height = info0.height; | |
213 GLsizei depth = info0.depth; | |
214 GLint levelCount = computeLevelCount(width, height, (m_target == GL_
TEXTURE_2D_ARRAY ? 0 : depth)); | |
215 size_t maxLevel = 0; | |
216 if (m_baseLevel + levelCount > 0) | |
217 maxLevel = m_baseLevel + levelCount - 1; | |
218 maxLevel = m_isWebGL2OrHigher ? std::min(m_maxLevel, maxLevel) : max
Level; | |
219 ASSERT(maxLevel < m_info[ii].size()); | |
220 for (size_t level = m_baseLevel + 1; level <= maxLevel; ++level) { | |
221 width = std::max(1, width >> 1); | |
222 height = std::max(1, height >> 1); | |
223 depth = m_target == GL_TEXTURE_2D_ARRAY ? depth : std::max(1, de
pth >> 1); | |
224 LevelInfo& info = m_info[ii][level]; | |
225 info.setInfo(info0.internalFormat, width, height, depth, info0.t
ype); | |
226 } | |
227 } | |
228 m_isComplete = true; | |
229 } | |
230 } | |
231 | |
232 GLenum WebGLTexture::getInternalFormat(GLenum target, GLint level) const | |
233 { | |
234 const LevelInfo* info = getLevelInfo(target, level); | |
235 if (!info) | |
236 return 0; | |
237 return info->internalFormat; | |
238 } | |
239 | |
240 GLenum WebGLTexture::getType(GLenum target, GLint level) const | |
241 { | |
242 const LevelInfo* info = getLevelInfo(target, level); | |
243 if (!info) | |
244 return 0; | |
245 return info->type; | |
246 } | |
247 | |
248 GLsizei WebGLTexture::getWidth(GLenum target, GLint level) const | |
249 { | |
250 const LevelInfo* info = getLevelInfo(target, level); | |
251 if (!info) | |
252 return 0; | |
253 return info->width; | |
254 } | |
255 | |
256 GLsizei WebGLTexture::getHeight(GLenum target, GLint level) const | |
257 { | |
258 const LevelInfo* info = getLevelInfo(target, level); | |
259 if (!info) | |
260 return 0; | |
261 return info->height; | |
262 } | |
263 | |
264 GLsizei WebGLTexture::getDepth(GLenum target, GLint level) const | |
265 { | |
266 const LevelInfo* info = getLevelInfo(target, level); | |
267 if (!info) | |
268 return 0; | |
269 return info->depth; | |
270 } | |
271 | |
272 bool WebGLTexture::isValid(GLenum target, GLint level) const | |
273 { | |
274 const LevelInfo* info = getLevelInfo(target, level); | |
275 if (!info) | |
276 return 0; | |
277 return info->valid; | |
278 } | |
279 | |
280 bool WebGLTexture::isNPOT(GLsizei width, GLsizei height) | 136 bool WebGLTexture::isNPOT(GLsizei width, GLsizei height) |
281 { | 137 { |
282 ASSERT(width >= 0 && height >= 0); | 138 ASSERT(width >= 0 && height >= 0); |
283 if (!width || !height) | 139 if (!width || !height) |
284 return false; | 140 return false; |
285 if ((width & (width - 1)) || (height & (height - 1))) | 141 if ((width & (width - 1)) || (height & (height - 1))) |
286 return true; | 142 return true; |
287 return false; | 143 return false; |
288 } | 144 } |
289 | 145 |
290 bool WebGLTexture::isNPOT() const | |
291 { | |
292 if (!object()) | |
293 return false; | |
294 return m_isNPOT; | |
295 } | |
296 | |
297 void WebGLTexture::deleteObjectImpl(WebGraphicsContext3D* context3d) | 146 void WebGLTexture::deleteObjectImpl(WebGraphicsContext3D* context3d) |
298 { | 147 { |
299 context3d->deleteTexture(m_object); | 148 context3d->deleteTexture(m_object); |
300 m_object = 0; | 149 m_object = 0; |
301 } | 150 } |
302 | 151 |
303 int WebGLTexture::mapTargetToIndex(GLenum target) const | 152 int WebGLTexture::mapTargetToIndex(GLenum target) const |
304 { | 153 { |
305 if (m_target == GL_TEXTURE_2D) { | 154 if (m_target == GL_TEXTURE_2D) { |
306 if (target == GL_TEXTURE_2D) | 155 if (target == GL_TEXTURE_2D) |
(...skipping 16 matching lines...) Expand all Loading... |
323 } else if (m_target == GL_TEXTURE_3D) { | 172 } else if (m_target == GL_TEXTURE_3D) { |
324 if (target == GL_TEXTURE_3D) | 173 if (target == GL_TEXTURE_3D) |
325 return 0; | 174 return 0; |
326 } else if (m_target == GL_TEXTURE_2D_ARRAY) { | 175 } else if (m_target == GL_TEXTURE_2D_ARRAY) { |
327 if (target == GL_TEXTURE_2D_ARRAY) | 176 if (target == GL_TEXTURE_2D_ARRAY) |
328 return 0; | 177 return 0; |
329 } | 178 } |
330 return -1; | 179 return -1; |
331 } | 180 } |
332 | 181 |
333 bool WebGLTexture::canGenerateMipmaps() | |
334 { | |
335 if (!m_isWebGL2OrHigher && isNPOT()) | |
336 return false; | |
337 | |
338 if (m_baseLevel >= m_info[0].size()) | |
339 return false; | |
340 | |
341 if (m_info.size() > 1 && !m_isCubeComplete) | |
342 return false; | |
343 | |
344 return true; | |
345 } | |
346 | |
347 GLint WebGLTexture::computeLevelCount(GLsizei width, GLsizei height, GLsizei dep
th) | 182 GLint WebGLTexture::computeLevelCount(GLsizei width, GLsizei height, GLsizei dep
th) |
348 { | 183 { |
349 // return 1 + log2Floor(std::max(width, height)); | 184 // return 1 + log2Floor(std::max(width, height)); |
350 GLsizei n = std::max(std::max(width, height), depth); | 185 GLsizei n = std::max(std::max(width, height), depth); |
351 if (n <= 0) | 186 if (n <= 0) |
352 return 0; | 187 return 0; |
353 GLint log = 0; | 188 GLint log = 0; |
354 GLsizei value = n; | 189 GLsizei value = n; |
355 for (int ii = 4; ii >= 0; --ii) { | 190 for (int ii = 4; ii >= 0; --ii) { |
356 int shift = (1 << ii); | 191 int shift = (1 << ii); |
357 GLsizei x = (value >> shift); | 192 GLsizei x = (value >> shift); |
358 if (x) { | 193 if (x) { |
359 value = x; | 194 value = x; |
360 log += shift; | 195 log += shift; |
361 } | 196 } |
362 } | 197 } |
363 ASSERT(value == 1); | 198 ASSERT(value == 1); |
364 return log + 1; | 199 return log + 1; |
365 } | 200 } |
366 | 201 |
367 void WebGLTexture::update() | |
368 { | |
369 m_isNPOT = false; | |
370 for (size_t ii = 0; ii < m_info.size(); ++ii) { | |
371 if (isNPOT(m_info[ii][0].width, m_info[ii][0].height)) { | |
372 m_isNPOT = true; | |
373 break; | |
374 } | |
375 } | |
376 m_isComplete = true; | |
377 m_isCubeComplete = true; | |
378 | |
379 if (m_baseLevel > m_maxLevel || m_baseLevel >= m_info[0].size()) { | |
380 m_isComplete = false; | |
381 } | |
382 else { | |
383 const LevelInfo& base = m_info[0][m_baseLevel]; | |
384 size_t levelCount = computeLevelCount(base.width, base.height, (m_target
== GL_TEXTURE_2D_ARRAY ? 0 : base.depth)); | |
385 size_t maxLevel = 0; | |
386 if (m_baseLevel + levelCount > 0) | |
387 maxLevel = m_baseLevel + levelCount - 1; | |
388 maxLevel = m_isWebGL2OrHigher ? std::min(m_maxLevel, maxLevel) : maxLeve
l; | |
389 for (size_t ii = 0; ii < m_info.size(); ++ii) { | |
390 const LevelInfo& info0 = m_info[ii][m_baseLevel]; | |
391 if (!info0.valid | |
392 || info0.width != base.width || info0.height != base.height || i
nfo0.depth != base.depth | |
393 || info0.internalFormat != base.internalFormat || info0.type !=
base.type | |
394 || (m_info.size() > 1 && info0.width != info0.height)) { | |
395 if (m_info.size() > 1) | |
396 m_isCubeComplete = false; | |
397 m_isComplete = false; | |
398 break; | |
399 } | |
400 | |
401 if (!m_isComplete) | |
402 continue; | |
403 GLsizei width = info0.width; | |
404 GLsizei height = info0.height; | |
405 GLsizei depth = info0.depth; | |
406 ASSERT(maxLevel < m_info[ii].size()); | |
407 for (size_t level = m_baseLevel + 1; level <= maxLevel; ++level) { | |
408 width = std::max(1, width >> 1); | |
409 height = std::max(1, height >> 1); | |
410 depth = m_target == GL_TEXTURE_2D_ARRAY ? depth : std::max(1, de
pth >> 1); | |
411 const LevelInfo& info = m_info[ii][level]; | |
412 if (!info.valid | |
413 || info.width != width || info.height != height || info.dept
h != depth | |
414 || info.internalFormat != info0.internalFormat || info.type
!= info0.type) { | |
415 m_isComplete = false; | |
416 break; | |
417 } | |
418 | |
419 } | |
420 } | |
421 } | |
422 m_isFloatType = m_info[0][0].type == GL_FLOAT; | |
423 m_isHalfFloatType = m_info[0][0].type == GL_HALF_FLOAT_OES; | |
424 } | |
425 | |
426 const WebGLTexture::LevelInfo* WebGLTexture::getLevelInfo(GLenum target, GLint l
evel) const | |
427 { | |
428 if (!object() || !m_target) | |
429 return nullptr; | |
430 int targetIndex = mapTargetToIndex(target); | |
431 if (targetIndex < 0 || targetIndex >= static_cast<int>(m_info.size())) | |
432 return nullptr; | |
433 if (level < 0 || level >= static_cast<GLint>(m_info[targetIndex].size())) | |
434 return nullptr; | |
435 return &(m_info[targetIndex][level]); | |
436 } | |
437 | |
438 // TODO(bajones): Logic surrounding relationship of internalFormat, format, and
type needs to be revisisted for WebGL 2.0 | 202 // TODO(bajones): Logic surrounding relationship of internalFormat, format, and
type needs to be revisisted for WebGL 2.0 |
439 GLenum WebGLTexture::getValidTypeForInternalFormat(GLenum internalFormat) | 203 GLenum WebGLTexture::getValidTypeForInternalFormat(GLenum internalFormat) |
440 { | 204 { |
441 switch (internalFormat) { | 205 switch (internalFormat) { |
442 case GL_R8: | 206 case GL_R8: |
443 return GL_UNSIGNED_BYTE; | 207 return GL_UNSIGNED_BYTE; |
444 case GL_R8_SNORM: | 208 case GL_R8_SNORM: |
445 return GL_BYTE; | 209 return GL_BYTE; |
446 case GL_R16F: | 210 case GL_R16F: |
447 return GL_HALF_FLOAT; | 211 return GL_HALF_FLOAT; |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
560 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: | 324 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: |
561 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: | 325 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: |
562 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: | 326 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: |
563 return GL_UNSIGNED_BYTE; | 327 return GL_UNSIGNED_BYTE; |
564 default: | 328 default: |
565 return GL_NONE; | 329 return GL_NONE; |
566 } | 330 } |
567 } | 331 } |
568 | 332 |
569 } // namespace blink | 333 } // namespace blink |
OLD | NEW |