1 #include "precompiled.h"
2 //
3 // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6 //
7
8 // Texture.cpp: Implements the gl::Texture class and its derived classes
9 // Texture2D and TextureCubeMap. Implements GL texture objects and related
10 // functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
11
12 #include "libGLESv2/Texture.h"
13
14 #include "libGLESv2/main.h"
15 #include "common/mathutil.h"
16 #include "common/utilities.h"
17 #include "libGLESv2/formatutils.h"
18 #include "libGLESv2/Renderbuffer.h"
19 #include "libGLESv2/renderer/Image.h"
20 #include "libGLESv2/renderer/Renderer.h"
21 #include "libGLESv2/renderer/TextureStorage.h"
22 #include "libEGL/Surface.h"
23 #include "libGLESv2/Buffer.h"
24 #include "libGLESv2/renderer/BufferStorage.h"
25 #include "libGLESv2/renderer/RenderTarget.h"
26
27 namespace gl
28 {
29
IsMipmapFiltered(const SamplerState & samplerState)30 bool IsMipmapFiltered(const SamplerState &samplerState)
31 {
32 switch (samplerState.minFilter)
33 {
34 case GL_NEAREST:
35 case GL_LINEAR:
36 return false;
37 case GL_NEAREST_MIPMAP_NEAREST:
38 case GL_LINEAR_MIPMAP_NEAREST:
39 case GL_NEAREST_MIPMAP_LINEAR:
40 case GL_LINEAR_MIPMAP_LINEAR:
41 return true;
42 default: UNREACHABLE();
43 return false;
44 }
45 }
46
IsRenderTargetUsage(GLenum usage)47 bool IsRenderTargetUsage(GLenum usage)
48 {
49 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
50 }
51
Texture(rx::Renderer * renderer,GLuint id,GLenum target)52 Texture::Texture(rx::Renderer *renderer, GLuint id, GLenum target) : RefCountObject(id)
53 {
54 mRenderer = renderer;
55
56 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
57 mSamplerState.magFilter = GL_LINEAR;
58 mSamplerState.wrapS = GL_REPEAT;
59 mSamplerState.wrapT = GL_REPEAT;
60 mSamplerState.wrapR = GL_REPEAT;
61 mSamplerState.maxAnisotropy = 1.0f;
62 mSamplerState.baseLevel = 0;
63 mSamplerState.maxLevel = 1000;
64 mSamplerState.minLod = -1000.0f;
65 mSamplerState.maxLod = 1000.0f;
66 mSamplerState.compareMode = GL_NONE;
67 mSamplerState.compareFunc = GL_LEQUAL;
68 mSamplerState.swizzleRed = GL_RED;
69 mSamplerState.swizzleGreen = GL_GREEN;
70 mSamplerState.swizzleBlue = GL_BLUE;
71 mSamplerState.swizzleAlpha = GL_ALPHA;
72 mUsage = GL_NONE;
73
74 mDirtyImages = true;
75
76 mImmutable = false;
77
78 mTarget = target;
79 }
80
~Texture()81 Texture::~Texture()
82 {
83 }
84
getTarget() const85 GLenum Texture::getTarget() const
86 {
87 return mTarget;
88 }
89
addProxyRef(const FramebufferAttachment * proxy)90 void Texture::addProxyRef(const FramebufferAttachment *proxy)
91 {
92 mRenderbufferProxies.addRef(proxy);
93 }
94
releaseProxy(const FramebufferAttachment * proxy)95 void Texture::releaseProxy(const FramebufferAttachment *proxy)
96 {
97 mRenderbufferProxies.release(proxy);
98 }
99
setMinFilter(GLenum filter)100 void Texture::setMinFilter(GLenum filter)
101 {
102 mSamplerState.minFilter = filter;
103 }
104
setMagFilter(GLenum filter)105 void Texture::setMagFilter(GLenum filter)
106 {
107 mSamplerState.magFilter = filter;
108 }
109
setWrapS(GLenum wrap)110 void Texture::setWrapS(GLenum wrap)
111 {
112 mSamplerState.wrapS = wrap;
113 }
114
setWrapT(GLenum wrap)115 void Texture::setWrapT(GLenum wrap)
116 {
117 mSamplerState.wrapT = wrap;
118 }
119
setWrapR(GLenum wrap)120 void Texture::setWrapR(GLenum wrap)
121 {
122 mSamplerState.wrapR = wrap;
123 }
124
setMaxAnisotropy(float textureMaxAnisotropy,float contextMaxAnisotropy)125 void Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
126 {
127 mSamplerState.maxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
128 }
129
setCompareMode(GLenum mode)130 void Texture::setCompareMode(GLenum mode)
131 {
132 mSamplerState.compareMode = mode;
133 }
134
setCompareFunc(GLenum func)135 void Texture::setCompareFunc(GLenum func)
136 {
137 mSamplerState.compareFunc = func;
138 }
139
setSwizzleRed(GLenum swizzle)140 void Texture::setSwizzleRed(GLenum swizzle)
141 {
142 mSamplerState.swizzleRed = swizzle;
143 }
144
setSwizzleGreen(GLenum swizzle)145 void Texture::setSwizzleGreen(GLenum swizzle)
146 {
147 mSamplerState.swizzleGreen = swizzle;
148 }
149
setSwizzleBlue(GLenum swizzle)150 void Texture::setSwizzleBlue(GLenum swizzle)
151 {
152 mSamplerState.swizzleBlue = swizzle;
153 }
154
setSwizzleAlpha(GLenum swizzle)155 void Texture::setSwizzleAlpha(GLenum swizzle)
156 {
157 mSamplerState.swizzleAlpha = swizzle;
158 }
159
setBaseLevel(GLint baseLevel)160 void Texture::setBaseLevel(GLint baseLevel)
161 {
162 mSamplerState.baseLevel = baseLevel;
163 }
164
setMaxLevel(GLint maxLevel)165 void Texture::setMaxLevel(GLint maxLevel)
166 {
167 mSamplerState.maxLevel = maxLevel;
168 }
169
setMinLod(GLfloat minLod)170 void Texture::setMinLod(GLfloat minLod)
171 {
172 mSamplerState.minLod = minLod;
173 }
174
setMaxLod(GLfloat maxLod)175 void Texture::setMaxLod(GLfloat maxLod)
176 {
177 mSamplerState.maxLod = maxLod;
178 }
179
setUsage(GLenum usage)180 void Texture::setUsage(GLenum usage)
181 {
182 mUsage = usage;
183 }
184
getMinFilter() const185 GLenum Texture::getMinFilter() const
186 {
187 return mSamplerState.minFilter;
188 }
189
getMagFilter() const190 GLenum Texture::getMagFilter() const
191 {
192 return mSamplerState.magFilter;
193 }
194
getWrapS() const195 GLenum Texture::getWrapS() const
196 {
197 return mSamplerState.wrapS;
198 }
199
getWrapT() const200 GLenum Texture::getWrapT() const
201 {
202 return mSamplerState.wrapT;
203 }
204
getWrapR() const205 GLenum Texture::getWrapR() const
206 {
207 return mSamplerState.wrapR;
208 }
209
getMaxAnisotropy() const210 float Texture::getMaxAnisotropy() const
211 {
212 return mSamplerState.maxAnisotropy;
213 }
214
getSwizzleRed() const215 GLenum Texture::getSwizzleRed() const
216 {
217 return mSamplerState.swizzleRed;
218 }
219
getSwizzleGreen() const220 GLenum Texture::getSwizzleGreen() const
221 {
222 return mSamplerState.swizzleGreen;
223 }
224
getSwizzleBlue() const225 GLenum Texture::getSwizzleBlue() const
226 {
227 return mSamplerState.swizzleBlue;
228 }
229
getSwizzleAlpha() const230 GLenum Texture::getSwizzleAlpha() const
231 {
232 return mSamplerState.swizzleAlpha;
233 }
234
getBaseLevel() const235 GLint Texture::getBaseLevel() const
236 {
237 return mSamplerState.baseLevel;
238 }
239
getMaxLevel() const240 GLint Texture::getMaxLevel() const
241 {
242 return mSamplerState.maxLevel;
243 }
244
getMinLod() const245 GLfloat Texture::getMinLod() const
246 {
247 return mSamplerState.minLod;
248 }
249
getMaxLod() const250 GLfloat Texture::getMaxLod() const
251 {
252 return mSamplerState.maxLod;
253 }
254
isSwizzled() const255 bool Texture::isSwizzled() const
256 {
257 return mSamplerState.swizzleRed != GL_RED ||
258 mSamplerState.swizzleGreen != GL_GREEN ||
259 mSamplerState.swizzleBlue != GL_BLUE ||
260 mSamplerState.swizzleAlpha != GL_ALPHA;
261 }
262
getSamplerState(SamplerState * sampler)263 void Texture::getSamplerState(SamplerState *sampler)
264 {
265 *sampler = mSamplerState;
266
267 // Offset the effective base level by the texture storage's top level
268 rx::TextureStorageInterface *texture = getNativeTexture();
269 int topLevel = texture ? texture->getTopLevel() : 0;
270 sampler->baseLevel = topLevel + mSamplerState.baseLevel;
271 }
272
getUsage() const273 GLenum Texture::getUsage() const
274 {
275 return mUsage;
276 }
277
getBaseLevelWidth() const278 GLint Texture::getBaseLevelWidth() const
279 {
280 const rx::Image *baseImage = getBaseLevelImage();
281 return (baseImage ? baseImage->getWidth() : 0);
282 }
283
getBaseLevelHeight() const284 GLint Texture::getBaseLevelHeight() const
285 {
286 const rx::Image *baseImage = getBaseLevelImage();
287 return (baseImage ? baseImage->getHeight() : 0);
288 }
289
getBaseLevelDepth() const290 GLint Texture::getBaseLevelDepth() const
291 {
292 const rx::Image *baseImage = getBaseLevelImage();
293 return (baseImage ? baseImage->getDepth() : 0);
294 }
295
296 // Note: "base level image" is loosely defined to be any image from the base level,
297 // where in the base of 2D array textures and cube maps there are several. Don't use
298 // the base level image for anything except querying texture format and size.
getBaseLevelInternalFormat() const299 GLenum Texture::getBaseLevelInternalFormat() const
300 {
301 const rx::Image *baseImage = getBaseLevelImage();
302 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
303 }
304
setImage(const PixelUnpackState & unpack,GLenum type,const void * pixels,rx::Image * image)305 void Texture::setImage(const PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
306 {
307 // No-op
308 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
309 {
310 return;
311 }
312
313 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
314 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
315 const void *pixelData = pixels;
316
317 if (unpack.pixelBuffer.id() != 0)
318 {
319 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
320 Buffer *pixelBuffer = unpack.pixelBuffer.get();
321 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
322 const void *bufferData = pixelBuffer->getStorage()->getData();
323 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
324 }
325
326 if (pixelData != NULL)
327 {
328 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
329 mDirtyImages = true;
330 }
331 }
332
isFastUnpackable(const PixelUnpackState & unpack,GLenum sizedInternalFormat)333 bool Texture::isFastUnpackable(const PixelUnpackState &unpack, GLenum sizedInternalFormat)
334 {
335 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
336 }
337
fastUnpackPixels(const PixelUnpackState & unpack,const void * pixels,const Box & destArea,GLenum sizedInternalFormat,GLenum type,rx::RenderTarget * destRenderTarget)338 bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
339 GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget)
340 {
341 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
342 {
343 return true;
344 }
345
346 // In order to perform the fast copy through the shader, we must have the right format, and be able
347 // to create a render target.
348 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
349
350 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
351
352 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
353 }
354
setCompressedImage(GLsizei imageSize,const void * pixels,rx::Image * image)355 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
356 {
357 if (pixels != NULL)
358 {
359 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
360 mDirtyImages = true;
361 }
362 }
363
subImage(GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,const PixelUnpackState & unpack,const void * pixels,rx::Image * image)364 bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
365 GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels, rx::Image *image)
366 {
367 const void *pixelData = pixels;
368
369 // CPU readback & copy where direct GPU copy is not supported
370 if (unpack.pixelBuffer.id() != 0)
371 {
372 Buffer *pixelBuffer = unpack.pixelBuffer.get();
373 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
374 const void *bufferData = pixelBuffer->getStorage()->getData();
375 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
376 }
377
378 if (pixelData != NULL)
379 {
380 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
381 mDirtyImages = true;
382 }
383
384 return true;
385 }
386
subImageCompressed(GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLsizei imageSize,const void * pixels,rx::Image * image)387 bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
388 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
389 {
390 if (pixels != NULL)
391 {
392 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
393 mDirtyImages = true;
394 }
395
396 return true;
397 }
398
getNativeTexture()399 rx::TextureStorageInterface *Texture::getNativeTexture()
400 {
401 // ensure the underlying texture is created
402 initializeStorage(false);
403
404 rx::TextureStorageInterface *storage = getBaseLevelStorage();
405 if (storage)
406 {
407 updateStorage();
408 }
409
410 return storage;
411 }
412
hasDirtyImages() const413 bool Texture::hasDirtyImages() const
414 {
415 return mDirtyImages;
416 }
417
resetDirty()418 void Texture::resetDirty()
419 {
420 mDirtyImages = false;
421 }
422
getTextureSerial()423 unsigned int Texture::getTextureSerial()
424 {
425 rx::TextureStorageInterface *texture = getNativeTexture();
426 return texture ? texture->getTextureSerial() : 0;
427 }
428
isImmutable() const429 bool Texture::isImmutable() const
430 {
431 return mImmutable;
432 }
433
immutableLevelCount()434 int Texture::immutableLevelCount()
435 {
436 return (mImmutable ? getNativeTexture()->getStorageInstance()->getLevelCount() : 0);
437 }
438
creationLevels(GLsizei width,GLsizei height,GLsizei depth) const439 GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
440 {
441 if ((isPow2(width) && isPow2(height) && isPow2(depth)) || mRenderer->getNonPower2TextureSupport())
442 {
443 // Maximum number of levels
444 return log2(std::max(std::max(width, height), depth)) + 1;
445 }
446 else
447 {
448 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
449 return 1;
450 }
451 }
452
mipLevels() const453 int Texture::mipLevels() const
454 {
455 return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
456 }
457
Texture2D(rx::Renderer * renderer,GLuint id)458 Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
459 {
460 mTexStorage = NULL;
461 mSurface = NULL;
462
463 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
464 {
465 mImageArray[i] = renderer->createImage();
466 }
467 }
468
~Texture2D()469 Texture2D::~Texture2D()
470 {
471 delete mTexStorage;
472 mTexStorage = NULL;
473
474 if (mSurface)
475 {
476 mSurface->setBoundTexture(NULL);
477 mSurface = NULL;
478 }
479
480 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
481 {
482 delete mImageArray[i];
483 }
484 }
485
getWidth(GLint level) const486 GLsizei Texture2D::getWidth(GLint level) const
487 {
488 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
489 return mImageArray[level]->getWidth();
490 else
491 return 0;
492 }
493
getHeight(GLint level) const494 GLsizei Texture2D::getHeight(GLint level) const
495 {
496 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
497 return mImageArray[level]->getHeight();
498 else
499 return 0;
500 }
501
getInternalFormat(GLint level) const502 GLenum Texture2D::getInternalFormat(GLint level) const
503 {
504 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
505 return mImageArray[level]->getInternalFormat();
506 else
507 return GL_NONE;
508 }
509
getActualFormat(GLint level) const510 GLenum Texture2D::getActualFormat(GLint level) const
511 {
512 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
513 return mImageArray[level]->getActualFormat();
514 else
515 return GL_NONE;
516 }
517
redefineImage(GLint level,GLenum internalformat,GLsizei width,GLsizei height)518 void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
519 {
520 releaseTexImage();
521
522 // If there currently is a corresponding storage texture image, it has these parameters
523 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
524 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
525 const GLenum storageFormat = getBaseLevelInternalFormat();
526
527 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
528
529 if (mTexStorage)
530 {
531 const int storageLevels = mTexStorage->getLevelCount();
532
533 if ((level >= storageLevels && storageLevels != 0) ||
534 width != storageWidth ||
535 height != storageHeight ||
536 internalformat != storageFormat) // Discard mismatched storage
537 {
538 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
539 {
540 mImageArray[i]->markDirty();
541 }
542
543 delete mTexStorage;
544 mTexStorage = NULL;
545 mDirtyImages = true;
546 }
547 }
548 }
549
setImage(GLint level,GLsizei width,GLsizei height,GLenum internalFormat,GLenum format,GLenum type,const PixelUnpackState & unpack,const void * pixels)550 void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
551 {
552 GLuint clientVersion = mRenderer->getCurrentClientVersion();
553 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
554 : GetSizedInternalFormat(format, type, clientVersion);
555 redefineImage(level, sizedInternalFormat, width, height);
556
557 bool fastUnpacked = false;
558
559 // Attempt a fast gpu copy of the pixel data to the surface
560 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
561 {
562 // Will try to create RT storage if it does not exist
563 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
564 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
565
566 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
567 {
568 // Ensure we don't overwrite our newly initialized data
569 mImageArray[level]->markClean();
570
571 fastUnpacked = true;
572 }
573 }
574
575 if (!fastUnpacked)
576 {
577 Texture::setImage(unpack, type, pixels, mImageArray[level]);
578 }
579 }
580
bindTexImage(egl::Surface * surface)581 void Texture2D::bindTexImage(egl::Surface *surface)
582 {
583 releaseTexImage();
584
585 GLenum internalformat = surface->getFormat();
586
587 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
588
589 delete mTexStorage;
590 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
591
592 mDirtyImages = true;
593 mSurface = surface;
594 mSurface->setBoundTexture(this);
595 }
596
releaseTexImage()597 void Texture2D::releaseTexImage()
598 {
599 if (mSurface)
600 {
601 mSurface->setBoundTexture(NULL);
602 mSurface = NULL;
603
604 if (mTexStorage)
605 {
606 delete mTexStorage;
607 mTexStorage = NULL;
608 }
609
610 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
611 {
612 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
613 }
614 }
615 }
616
setCompressedImage(GLint level,GLenum format,GLsizei width,GLsizei height,GLsizei imageSize,const void * pixels)617 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
618 {
619 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
620 redefineImage(level, format, width, height);
621
622 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
623 }
624
commitRect(GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height)625 void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
626 {
627 if (isValidLevel(level))
628 {
629 rx::Image *image = mImageArray[level];
630 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
631 {
632 image->markClean();
633 }
634 }
635 }
636
subImage(GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const PixelUnpackState & unpack,const void * pixels)637 void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
638 {
639 bool fastUnpacked = false;
640
641 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
642 {
643 rx::RenderTarget *renderTarget = getRenderTarget(level);
644 Box destArea(xoffset, yoffset, 0, width, height, 1);
645
646 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
647 {
648 // Ensure we don't overwrite our newly initialized data
649 mImageArray[level]->markClean();
650
651 fastUnpacked = true;
652 }
653 }
654
655 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
656 {
657 commitRect(level, xoffset, yoffset, width, height);
658 }
659 }
660
subImageCompressed(GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLsizei imageSize,const void * pixels)661 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
662 {
663 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
664 {
665 commitRect(level, xoffset, yoffset, width, height);
666 }
667 }
668
copyImage(GLint level,GLenum format,GLint x,GLint y,GLsizei width,GLsizei height,Framebuffer * source)669 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
670 {
671 GLuint clientVersion = mRenderer->getCurrentClientVersion();
672 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
673 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
674 redefineImage(level, sizedInternalFormat, width, height);
675
676 if (!mImageArray[level]->isRenderableFormat())
677 {
678 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
679 mDirtyImages = true;
680 }
681 else
682 {
683 ensureRenderTarget();
684 mImageArray[level]->markClean();
685
686 if (width != 0 && height != 0 && isValidLevel(level))
687 {
688 gl::Rectangle sourceRect;
689 sourceRect.x = x;
690 sourceRect.width = width;
691 sourceRect.y = y;
692 sourceRect.height = height;
693
694 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
695 }
696 }
697 }
698
copySubImage(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLint x,GLint y,GLsizei width,GLsizei height,Framebuffer * source)699 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
700 {
701 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
702 // the current level we're copying to is defined (with appropriate format, width & height)
703 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
704
705 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
706 {
707 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
708 mDirtyImages = true;
709 }
710 else
711 {
712 ensureRenderTarget();
713
714 if (isValidLevel(level))
715 {
716 updateStorageLevel(level);
717
718 GLuint clientVersion = mRenderer->getCurrentClientVersion();
719
720 gl::Rectangle sourceRect;
721 sourceRect.x = x;
722 sourceRect.width = width;
723 sourceRect.y = y;
724 sourceRect.height = height;
725
726 mRenderer->copyImage(source, sourceRect,
727 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
728 xoffset, yoffset, mTexStorage, level);
729 }
730 }
731 }
732
storage(GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height)733 void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
734 {
735 for (int level = 0; level < levels; level++)
736 {
737 GLsizei levelWidth = std::max(1, width >> level);
738 GLsizei levelHeight = std::max(1, height >> level);
739 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
740 }
741
742 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
743 {
744 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
745 }
746
747 mImmutable = true;
748
749 setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
750 }
751
setCompleteTexStorage(rx::TextureStorageInterface2D * newCompleteTexStorage)752 void Texture2D::setCompleteTexStorage(rx::TextureStorageInterface2D *newCompleteTexStorage)
753 {
754 SafeDelete(mTexStorage);
755 mTexStorage = newCompleteTexStorage;
756
757 if (mTexStorage && mTexStorage->isManaged())
758 {
759 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
760 {
761 mImageArray[level]->setManagedSurface(mTexStorage, level);
762 }
763 }
764
765 mDirtyImages = true;
766 }
767
768 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
isSamplerComplete(const SamplerState & samplerState) const769 bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
770 {
771 GLsizei width = getBaseLevelWidth();
772 GLsizei height = getBaseLevelHeight();
773
774 if (width <= 0 || height <= 0)
775 {
776 return false;
777 }
778
779 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
780 {
781 if (samplerState.magFilter != GL_NEAREST ||
782 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
783 {
784 return false;
785 }
786 }
787
788 bool npotSupport = mRenderer->getNonPower2TextureSupport();
789
790 if (!npotSupport)
791 {
792 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
793 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
794 {
795 return false;
796 }
797 }
798
799 if (IsMipmapFiltered(samplerState))
800 {
801 if (!npotSupport)
802 {
803 if (!isPow2(width) || !isPow2(height))
804 {
805 return false;
806 }
807 }
808
809 if (!isMipmapComplete())
810 {
811 return false;
812 }
813 }
814
815 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
816 // The internalformat specified for the texture arrays is a sized internal depth or
817 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
818 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
819 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
820 if (gl::GetDepthBits(getInternalFormat(0), mRenderer->getCurrentClientVersion()) > 0 &&
821 mRenderer->getCurrentClientVersion() > 2)
822 {
823 if (mSamplerState.compareMode == GL_NONE)
824 {
825 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
826 mSamplerState.magFilter != GL_NEAREST)
827 {
828 return false;
829 }
830 }
831 }
832
833 return true;
834 }
835
836 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
isMipmapComplete() const837 bool Texture2D::isMipmapComplete() const
838 {
839 int levelCount = mipLevels();
840
841 for (int level = 0; level < levelCount; level++)
842 {
843 if (!isLevelComplete(level))
844 {
845 return false;
846 }
847 }
848
849 return true;
850 }
851
isLevelComplete(int level) const852 bool Texture2D::isLevelComplete(int level) const
853 {
854 if (isImmutable())
855 {
856 return true;
857 }
858
859 const rx::Image *baseImage = getBaseLevelImage();
860
861 GLsizei width = baseImage->getWidth();
862 GLsizei height = baseImage->getHeight();
863
864 if (width <= 0 || height <= 0)
865 {
866 return false;
867 }
868
869 // The base image level is complete if the width and height are positive
870 if (level == 0)
871 {
872 return true;
873 }
874
875 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
876 rx::Image *image = mImageArray[level];
877
878 if (image->getInternalFormat() != baseImage->getInternalFormat())
879 {
880 return false;
881 }
882
883 if (image->getWidth() != std::max(1, width >> level))
884 {
885 return false;
886 }
887
888 if (image->getHeight() != std::max(1, height >> level))
889 {
890 return false;
891 }
892
893 return true;
894 }
895
isCompressed(GLint level) const896 bool Texture2D::isCompressed(GLint level) const
897 {
898 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
899 }
900
isDepth(GLint level) const901 bool Texture2D::isDepth(GLint level) const
902 {
903 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
904 }
905
906 // Constructs a native texture resource from the texture images
initializeStorage(bool renderTarget)907 void Texture2D::initializeStorage(bool renderTarget)
908 {
909 // Only initialize the first time this texture is used as a render target or shader resource
910 if (mTexStorage)
911 {
912 return;
913 }
914
915 // do not attempt to create storage for nonexistant data
916 if (!isLevelComplete(0))
917 {
918 return;
919 }
920
921 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
922
923 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
924 ASSERT(mTexStorage);
925
926 // flush image data to the storage
927 updateStorage();
928 }
929
createCompleteStorage(bool renderTarget) const930 rx::TextureStorageInterface2D *Texture2D::createCompleteStorage(bool renderTarget) const
931 {
932 GLsizei width = getBaseLevelWidth();
933 GLsizei height = getBaseLevelHeight();
934
935 ASSERT(width > 0 && height > 0);
936
937 // use existing storage level count, when previously specified by TexStorage*D
938 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
939
940 return new rx::TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
941 }
942
updateStorage()943 void Texture2D::updateStorage()
944 {
945 ASSERT(mTexStorage != NULL);
946 GLint storageLevels = mTexStorage->getLevelCount();
947 for (int level = 0; level < storageLevels; level++)
948 {
949 if (mImageArray[level]->isDirty() && isLevelComplete(level))
950 {
951 updateStorageLevel(level);
952 }
953 }
954 }
955
updateStorageLevel(int level)956 void Texture2D::updateStorageLevel(int level)
957 {
958 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
959 ASSERT(isLevelComplete(level));
960
961 if (mImageArray[level]->isDirty())
962 {
963 commitRect(level, 0, 0, getWidth(level), getHeight(level));
964 }
965 }
966
ensureRenderTarget()967 bool Texture2D::ensureRenderTarget()
968 {
969 initializeStorage(true);
970
971 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
972 {
973 ASSERT(mTexStorage);
974 if (!mTexStorage->isRenderTarget())
975 {
976 rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
977
978 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
979 {
980 delete newRenderTargetStorage;
981 return gl::error(GL_OUT_OF_MEMORY, false);
982 }
983
984 setCompleteTexStorage(newRenderTargetStorage);
985 }
986 }
987
988 return (mTexStorage && mTexStorage->isRenderTarget());
989 }
990
generateMipmaps()991 void Texture2D::generateMipmaps()
992 {
993 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
994 int levelCount = mipLevels();
995 for (int level = 1; level < levelCount; level++)
996 {
997 redefineImage(level, getBaseLevelInternalFormat(),
998 std::max(getBaseLevelWidth() >> level, 1),
999 std::max(getBaseLevelHeight() >> level, 1));
1000 }
1001
1002 if (mTexStorage && mTexStorage->isRenderTarget())
1003 {
1004 for (int level = 1; level < levelCount; level++)
1005 {
1006 mTexStorage->generateMipmap(level);
1007
1008 mImageArray[level]->markClean();
1009 }
1010 }
1011 else
1012 {
1013 for (int level = 1; level < levelCount; level++)
1014 {
1015 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1016 }
1017 }
1018 }
1019
getBaseLevelImage() const1020 const rx::Image *Texture2D::getBaseLevelImage() const
1021 {
1022 return mImageArray[0];
1023 }
1024
getBaseLevelStorage()1025 rx::TextureStorageInterface *Texture2D::getBaseLevelStorage()
1026 {
1027 return mTexStorage;
1028 }
1029
getAttachment(GLint level)1030 FramebufferAttachment *Texture2D::getAttachment(GLint level)
1031 {
1032 FramebufferAttachment *attachment = mRenderbufferProxies.get(level, 0);
1033 if (!attachment)
1034 {
1035 attachment = new FramebufferAttachment(mRenderer, id(), new Texture2DAttachment(this, level));
1036 mRenderbufferProxies.add(level, 0, attachment);
1037 }
1038
1039 return attachment;
1040 }
1041
getRenderTargetSerial(GLint level)1042 unsigned int Texture2D::getRenderTargetSerial(GLint level)
1043 {
1044 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
1045 }
1046
getRenderTarget(GLint level)1047 rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
1048 {
1049 // ensure the underlying texture is created
1050 if (!ensureRenderTarget())
1051 {
1052 return NULL;
1053 }
1054
1055 updateStorageLevel(level);
1056
1057 // ensure this is NOT a depth texture
1058 if (isDepth(level))
1059 {
1060 return NULL;
1061 }
1062
1063 return mTexStorage->getRenderTarget(level);
1064 }
1065
getDepthSencil(GLint level)1066 rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
1067 {
1068 // ensure the underlying texture is created
1069 if (!ensureRenderTarget())
1070 {
1071 return NULL;
1072 }
1073
1074 updateStorageLevel(level);
1075
1076 // ensure this is actually a depth texture
1077 if (!isDepth(level))
1078 {
1079 return NULL;
1080 }
1081
1082 return mTexStorage->getRenderTarget(level);
1083 }
1084
isValidLevel(int level) const1085 bool Texture2D::isValidLevel(int level) const
1086 {
1087 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
1088 }
1089
TextureCubeMap(rx::Renderer * renderer,GLuint id)1090 TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
1091 {
1092 mTexStorage = NULL;
1093 for (int i = 0; i < 6; i++)
1094 {
1095 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1096 {
1097 mImageArray[i][j] = renderer->createImage();
1098 }
1099 }
1100 }
1101
~TextureCubeMap()1102 TextureCubeMap::~TextureCubeMap()
1103 {
1104 for (int i = 0; i < 6; i++)
1105 {
1106 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1107 {
1108 delete mImageArray[i][j];
1109 }
1110 }
1111
1112 delete mTexStorage;
1113 mTexStorage = NULL;
1114 }
1115
getWidth(GLenum target,GLint level) const1116 GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
1117 {
1118 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1119 return mImageArray[targetToIndex(target)][level]->getWidth();
1120 else
1121 return 0;
1122 }
1123
getHeight(GLenum target,GLint level) const1124 GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
1125 {
1126 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1127 return mImageArray[targetToIndex(target)][level]->getHeight();
1128 else
1129 return 0;
1130 }
1131
getInternalFormat(GLenum target,GLint level) const1132 GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
1133 {
1134 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1135 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
1136 else
1137 return GL_NONE;
1138 }
1139
getActualFormat(GLenum target,GLint level) const1140 GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
1141 {
1142 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1143 return mImageArray[targetToIndex(target)][level]->getActualFormat();
1144 else
1145 return GL_NONE;
1146 }
1147
setImagePosX(GLint level,GLsizei width,GLsizei height,GLenum internalFormat,GLenum format,GLenum type,const PixelUnpackState & unpack,const void * pixels)1148 void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1149 {
1150 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
1151 }
1152
setImageNegX(GLint level,GLsizei width,GLsizei height,GLenum internalFormat,GLenum format,GLenum type,const PixelUnpackState & unpack,const void * pixels)1153 void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1154 {
1155 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
1156 }
1157
setImagePosY(GLint level,GLsizei width,GLsizei height,GLenum internalFormat,GLenum format,GLenum type,const PixelUnpackState & unpack,const void * pixels)1158 void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1159 {
1160 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
1161 }
1162
setImageNegY(GLint level,GLsizei width,GLsizei height,GLenum internalFormat,GLenum format,GLenum type,const PixelUnpackState & unpack,const void * pixels)1163 void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1164 {
1165 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
1166 }
1167
setImagePosZ(GLint level,GLsizei width,GLsizei height,GLenum internalFormat,GLenum format,GLenum type,const PixelUnpackState & unpack,const void * pixels)1168 void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1169 {
1170 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
1171 }
1172
setImageNegZ(GLint level,GLsizei width,GLsizei height,GLenum internalFormat,GLenum format,GLenum type,const PixelUnpackState & unpack,const void * pixels)1173 void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1174 {
1175 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
1176 }
1177
setCompressedImage(GLenum target,GLint level,GLenum format,GLsizei width,GLsizei height,GLsizei imageSize,const void * pixels)1178 void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
1179 {
1180 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1181 int faceIndex = targetToIndex(target);
1182 redefineImage(faceIndex, level, format, width, height);
1183
1184 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
1185 }
1186
commitRect(int faceIndex,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height)1187 void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1188 {
1189 if (isValidFaceLevel(faceIndex, level))
1190 {
1191 rx::Image *image = mImageArray[faceIndex][level];
1192 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
1193 image->markClean();
1194 }
1195 }
1196
subImage(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const PixelUnpackState & unpack,const void * pixels)1197 void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1198 {
1199 int faceIndex = targetToIndex(target);
1200 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
1201 {
1202 commitRect(faceIndex, level, xoffset, yoffset, width, height);
1203 }
1204 }
1205
subImageCompressed(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLsizei imageSize,const void * pixels)1206 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1207 {
1208 int faceIndex = targetToIndex(target);
1209 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
1210 {
1211 commitRect(faceIndex, level, xoffset, yoffset, width, height);
1212 }
1213 }
1214
1215 // Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
isSamplerComplete(const SamplerState & samplerState) const1216 bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
1217 {
1218 int size = getBaseLevelWidth();
1219
1220 bool mipmapping = IsMipmapFiltered(samplerState);
1221
1222 if (!IsTextureFilteringSupported(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0), mRenderer))
1223 {
1224 if (samplerState.magFilter != GL_NEAREST ||
1225 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
1226 {
1227 return false;
1228 }
1229 }
1230
1231 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
1232 {
1233 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
1234 {
1235 return false;
1236 }
1237 }
1238
1239 if (!mipmapping)
1240 {
1241 if (!isCubeComplete())
1242 {
1243 return false;
1244 }
1245 }
1246 else
1247 {
1248 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1249 {
1250 return false;
1251 }
1252 }
1253
1254 return true;
1255 }
1256
1257 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
isCubeComplete() const1258 bool TextureCubeMap::isCubeComplete() const
1259 {
1260 int baseWidth = getBaseLevelWidth();
1261 int baseHeight = getBaseLevelHeight();
1262 GLenum baseFormat = getBaseLevelInternalFormat();
1263
1264 if (baseWidth <= 0 || baseWidth != baseHeight)
1265 {
1266 return false;
1267 }
1268
1269 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1270 {
1271 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
1272
1273 if (faceBaseImage.getWidth() != baseWidth ||
1274 faceBaseImage.getHeight() != baseHeight ||
1275 faceBaseImage.getInternalFormat() != baseFormat )
1276 {
1277 return false;
1278 }
1279 }
1280
1281 return true;
1282 }
1283
isMipmapCubeComplete() const1284 bool TextureCubeMap::isMipmapCubeComplete() const
1285 {
1286 if (isImmutable())
1287 {
1288 return true;
1289 }
1290
1291 if (!isCubeComplete())
1292 {
1293 return false;
1294 }
1295
1296 int levelCount = mipLevels();
1297
1298 for (int face = 0; face < 6; face++)
1299 {
1300 for (int level = 1; level < levelCount; level++)
1301 {
1302 if (!isFaceLevelComplete(face, level))
1303 {
1304 return false;
1305 }
1306 }
1307 }
1308
1309 return true;
1310 }
1311
isFaceLevelComplete(int faceIndex,int level) const1312 bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
1313 {
1314 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1315
1316 if (isImmutable())
1317 {
1318 return true;
1319 }
1320
1321 int baseSize = getBaseLevelWidth();
1322
1323 if (baseSize <= 0)
1324 {
1325 return false;
1326 }
1327
1328 // "isCubeComplete" checks for base level completeness and we must call that
1329 // to determine if any face at level 0 is complete. We omit that check here
1330 // to avoid re-checking cube-completeness for every face at level 0.
1331 if (level == 0)
1332 {
1333 return true;
1334 }
1335
1336 // Check that non-zero levels are consistent with the base level.
1337 const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
1338
1339 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1340 {
1341 return false;
1342 }
1343
1344 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1345 {
1346 return false;
1347 }
1348
1349 return true;
1350 }
1351
isCompressed(GLenum target,GLint level) const1352 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1353 {
1354 return IsFormatCompressed(getInternalFormat(target, level), mRenderer->getCurrentClientVersion());
1355 }
1356
isDepth(GLenum target,GLint level) const1357 bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1358 {
1359 return GetDepthBits(getInternalFormat(target, level), mRenderer->getCurrentClientVersion()) > 0;
1360 }
1361
initializeStorage(bool renderTarget)1362 void TextureCubeMap::initializeStorage(bool renderTarget)
1363 {
1364 // Only initialize the first time this texture is used as a render target or shader resource
1365 if (mTexStorage)
1366 {
1367 return;
1368 }
1369
1370 // do not attempt to create storage for nonexistant data
1371 if (!isFaceLevelComplete(0, 0))
1372 {
1373 return;
1374 }
1375
1376 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1377
1378 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1379 ASSERT(mTexStorage);
1380
1381 // flush image data to the storage
1382 updateStorage();
1383 }
1384
createCompleteStorage(bool renderTarget) const1385 rx::TextureStorageInterfaceCube *TextureCubeMap::createCompleteStorage(bool renderTarget) const
1386 {
1387 GLsizei size = getBaseLevelWidth();
1388
1389 ASSERT(size > 0);
1390
1391 // use existing storage level count, when previously specified by TexStorage*D
1392 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1393
1394 return new rx::TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
1395 }
1396
setCompleteTexStorage(rx::TextureStorageInterfaceCube * newCompleteTexStorage)1397 void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage)
1398 {
1399 SafeDelete(mTexStorage);
1400 mTexStorage = newCompleteTexStorage;
1401
1402 if (mTexStorage && mTexStorage->isManaged())
1403 {
1404 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1405 {
1406 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1407 {
1408 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
1409 }
1410 }
1411 }
1412
1413 mDirtyImages = true;
1414 }
1415
updateStorage()1416 void TextureCubeMap::updateStorage()
1417 {
1418 ASSERT(mTexStorage != NULL);
1419 GLint storageLevels = mTexStorage->getLevelCount();
1420 for (int face = 0; face < 6; face++)
1421 {
1422 for (int level = 0; level < storageLevels; level++)
1423 {
1424 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1425 {
1426 updateStorageFaceLevel(face, level);
1427 }
1428 }
1429 }
1430 }
1431
updateStorageFaceLevel(int faceIndex,int level)1432 void TextureCubeMap::updateStorageFaceLevel(int faceIndex, int level)
1433 {
1434 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1435 rx::Image *image = mImageArray[faceIndex][level];
1436
1437 if (image->isDirty())
1438 {
1439 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1440 }
1441 }
1442
ensureRenderTarget()1443 bool TextureCubeMap::ensureRenderTarget()
1444 {
1445 initializeStorage(true);
1446
1447 if (getBaseLevelWidth() > 0)
1448 {
1449 ASSERT(mTexStorage);
1450 if (!mTexStorage->isRenderTarget())
1451 {
1452 rx::TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1453
1454 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1455 {
1456 delete newRenderTargetStorage;
1457 return gl::error(GL_OUT_OF_MEMORY, false);
1458 }
1459
1460 setCompleteTexStorage(newRenderTargetStorage);
1461 }
1462 }
1463
1464 return (mTexStorage && mTexStorage->isRenderTarget());
1465 }
1466
setImage(int faceIndex,GLint level,GLsizei width,GLsizei height,GLenum internalFormat,GLenum format,GLenum type,const PixelUnpackState & unpack,const void * pixels)1467 void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1468 {
1469 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1470 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1471 : GetSizedInternalFormat(format, type, clientVersion);
1472
1473 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1474
1475 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
1476 }
1477
targetToIndex(GLenum target)1478 int TextureCubeMap::targetToIndex(GLenum target)
1479 {
1480 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1481 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1482 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1483 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1484 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1485
1486 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1487 }
1488
redefineImage(int faceIndex,GLint level,GLenum internalformat,GLsizei width,GLsizei height)1489 void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1490 {
1491 // If there currently is a corresponding storage texture image, it has these parameters
1492 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1493 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1494 const GLenum storageFormat = getBaseLevelInternalFormat();
1495
1496 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1497
1498 if (mTexStorage)
1499 {
1500 const int storageLevels = mTexStorage->getLevelCount();
1501
1502 if ((level >= storageLevels && storageLevels != 0) ||
1503 width != storageWidth ||
1504 height != storageHeight ||
1505 internalformat != storageFormat) // Discard mismatched storage
1506 {
1507 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1508 {
1509 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1510 {
1511 mImageArray[faceIndex][level]->markDirty();
1512 }
1513 }
1514
1515 delete mTexStorage;
1516 mTexStorage = NULL;
1517
1518 mDirtyImages = true;
1519 }
1520 }
1521 }
1522
copyImage(GLenum target,GLint level,GLenum format,GLint x,GLint y,GLsizei width,GLsizei height,Framebuffer * source)1523 void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1524 {
1525 int faceIndex = targetToIndex(target);
1526 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1527 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format
1528 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE, clientVersion);
1529 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1530
1531 if (!mImageArray[faceIndex][level]->isRenderableFormat())
1532 {
1533 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1534 mDirtyImages = true;
1535 }
1536 else
1537 {
1538 ensureRenderTarget();
1539 mImageArray[faceIndex][level]->markClean();
1540
1541 ASSERT(width == height);
1542
1543 if (width > 0 && isValidFaceLevel(faceIndex, level))
1544 {
1545 gl::Rectangle sourceRect;
1546 sourceRect.x = x;
1547 sourceRect.width = width;
1548 sourceRect.y = y;
1549 sourceRect.height = height;
1550
1551 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
1552 }
1553 }
1554 }
1555
copySubImage(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLint x,GLint y,GLsizei width,GLsizei height,Framebuffer * source)1556 void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1557 {
1558 int faceIndex = targetToIndex(target);
1559
1560 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1561 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1562 // rely on the "getBaseLevel*" methods reliably otherwise.
1563 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1564
1565 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1566 {
1567 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1568 mDirtyImages = true;
1569 }
1570 else
1571 {
1572 ensureRenderTarget();
1573
1574 if (isValidFaceLevel(faceIndex, level))
1575 {
1576 updateStorageFaceLevel(faceIndex, level);
1577
1578 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1579
1580 gl::Rectangle sourceRect;
1581 sourceRect.x = x;
1582 sourceRect.width = width;
1583 sourceRect.y = y;
1584 sourceRect.height = height;
1585
1586 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
1587 xoffset, yoffset, mTexStorage, target, level);
1588 }
1589 }
1590 }
1591
storage(GLsizei levels,GLenum internalformat,GLsizei size)1592 void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1593 {
1594 for (int level = 0; level < levels; level++)
1595 {
1596 GLsizei mipSize = std::max(1, size >> level);
1597 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1598 {
1599 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1600 }
1601 }
1602
1603 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1604 {
1605 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1606 {
1607 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1608 }
1609 }
1610
1611 mImmutable = true;
1612
1613 setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), size, levels));
1614 }
1615
generateMipmaps()1616 void TextureCubeMap::generateMipmaps()
1617 {
1618 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1619 int levelCount = mipLevels();
1620 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1621 {
1622 for (int level = 1; level < levelCount; level++)
1623 {
1624 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1625 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1626 }
1627 }
1628
1629 if (mTexStorage && mTexStorage->isRenderTarget())
1630 {
1631 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1632 {
1633 for (int level = 1; level < levelCount; level++)
1634 {
1635 mTexStorage->generateMipmap(faceIndex, level);
1636
1637 mImageArray[faceIndex][level]->markClean();
1638 }
1639 }
1640 }
1641 else
1642 {
1643 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1644 {
1645 for (int level = 1; level < levelCount; level++)
1646 {
1647 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
1648 }
1649 }
1650 }
1651 }
1652
getBaseLevelImage() const1653 const rx::Image *TextureCubeMap::getBaseLevelImage() const
1654 {
1655 // Note: if we are not cube-complete, there is no single base level image that can describe all
1656 // cube faces, so this method is only well-defined for a cube-complete base level.
1657 return mImageArray[0][0];
1658 }
1659
getBaseLevelStorage()1660 rx::TextureStorageInterface *TextureCubeMap::getBaseLevelStorage()
1661 {
1662 return mTexStorage;
1663 }
1664
getAttachment(GLenum target,GLint level)1665 FramebufferAttachment *TextureCubeMap::getAttachment(GLenum target, GLint level)
1666 {
1667 ASSERT(!IsCubemapTextureTarget(target));
1668 int faceIndex = targetToIndex(target);
1669
1670 FramebufferAttachment *attachment = mRenderbufferProxies.get(level, faceIndex);
1671 if (!attachment)
1672 {
1673 attachment = new FramebufferAttachment(mRenderer, id(), new TextureCubeMapAttachment(this, target, level));
1674 mRenderbufferProxies.add(level, faceIndex, attachment);
1675 }
1676
1677 return attachment;
1678 }
1679
getRenderTargetSerial(GLenum target,GLint level)1680 unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level)
1681 {
1682 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
1683 }
1684
getRenderTarget(GLenum target,GLint level)1685 rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
1686 {
1687 ASSERT(IsCubemapTextureTarget(target));
1688
1689 // ensure the underlying texture is created
1690 if (!ensureRenderTarget())
1691 {
1692 return NULL;
1693 }
1694
1695 updateStorageFaceLevel(targetToIndex(target), level);
1696
1697 // ensure this is NOT a depth texture
1698 if (isDepth(target, level))
1699 {
1700 return NULL;
1701 }
1702
1703 return mTexStorage->getRenderTarget(target, level);
1704 }
1705
getDepthStencil(GLenum target,GLint level)1706 rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1707 {
1708 ASSERT(IsCubemapTextureTarget(target));
1709
1710 // ensure the underlying texture is created
1711 if (!ensureRenderTarget())
1712 {
1713 return NULL;
1714 }
1715
1716 updateStorageFaceLevel(targetToIndex(target), level);
1717
1718 // ensure this is a depth texture
1719 if (!isDepth(target, level))
1720 {
1721 return NULL;
1722 }
1723
1724 return mTexStorage->getRenderTarget(target, level);
1725 }
1726
isValidFaceLevel(int faceIndex,int level) const1727 bool TextureCubeMap::isValidFaceLevel(int faceIndex, int level) const
1728 {
1729 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1730 }
1731
Texture3D(rx::Renderer * renderer,GLuint id)1732 Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
1733 {
1734 mTexStorage = NULL;
1735
1736 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1737 {
1738 mImageArray[i] = renderer->createImage();
1739 }
1740 }
1741
~Texture3D()1742 Texture3D::~Texture3D()
1743 {
1744 delete mTexStorage;
1745 mTexStorage = NULL;
1746
1747 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1748 {
1749 delete mImageArray[i];
1750 }
1751 }
1752
getWidth(GLint level) const1753 GLsizei Texture3D::getWidth(GLint level) const
1754 {
1755 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1756 }
1757
getHeight(GLint level) const1758 GLsizei Texture3D::getHeight(GLint level) const
1759 {
1760 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1761 }
1762
getDepth(GLint level) const1763 GLsizei Texture3D::getDepth(GLint level) const
1764 {
1765 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1766 }
1767
getInternalFormat(GLint level) const1768 GLenum Texture3D::getInternalFormat(GLint level) const
1769 {
1770 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1771 }
1772
getActualFormat(GLint level) const1773 GLenum Texture3D::getActualFormat(GLint level) const
1774 {
1775 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : GL_NONE;
1776 }
1777
isCompressed(GLint level) const1778 bool Texture3D::isCompressed(GLint level) const
1779 {
1780 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
1781 }
1782
isDepth(GLint level) const1783 bool Texture3D::isDepth(GLint level) const
1784 {
1785 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
1786 }
1787
setImage(GLint level,GLsizei width,GLsizei height,GLsizei depth,GLenum internalFormat,GLenum format,GLenum type,const PixelUnpackState & unpack,const void * pixels)1788 void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1789 {
1790 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1791 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
1792 : GetSizedInternalFormat(format, type, clientVersion);
1793 redefineImage(level, sizedInternalFormat, width, height, depth);
1794
1795 bool fastUnpacked = false;
1796
1797 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1798 if (isFastUnpackable(unpack, sizedInternalFormat))
1799 {
1800 // Will try to create RT storage if it does not exist
1801 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1802 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1803
1804 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1805 {
1806 // Ensure we don't overwrite our newly initialized data
1807 mImageArray[level]->markClean();
1808
1809 fastUnpacked = true;
1810 }
1811 }
1812
1813 if (!fastUnpacked)
1814 {
1815 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1816 }
1817 }
1818
setCompressedImage(GLint level,GLenum format,GLsizei width,GLsizei height,GLsizei depth,GLsizei imageSize,const void * pixels)1819 void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1820 {
1821 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1822 redefineImage(level, format, width, height, depth);
1823
1824 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1825 }
1826
subImage(GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,const PixelUnpackState & unpack,const void * pixels)1827 void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
1828 {
1829 bool fastUnpacked = false;
1830
1831 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1832 if (isFastUnpackable(unpack, getInternalFormat(level)))
1833 {
1834 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1835 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1836
1837 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1838 {
1839 // Ensure we don't overwrite our newly initialized data
1840 mImageArray[level]->markClean();
1841
1842 fastUnpacked = true;
1843 }
1844 }
1845
1846 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
1847 {
1848 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1849 }
1850 }
1851
subImageCompressed(GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLsizei imageSize,const void * pixels)1852 void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1853 {
1854 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1855 {
1856 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1857 }
1858 }
1859
storage(GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth)1860 void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1861 {
1862 for (int level = 0; level < levels; level++)
1863 {
1864 GLsizei levelWidth = std::max(1, width >> level);
1865 GLsizei levelHeight = std::max(1, height >> level);
1866 GLsizei levelDepth = std::max(1, depth >> level);
1867 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1868 }
1869
1870 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1871 {
1872 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1873 }
1874
1875 mImmutable = true;
1876
1877 setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
1878 }
1879
generateMipmaps()1880 void Texture3D::generateMipmaps()
1881 {
1882 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1883 int levelCount = mipLevels();
1884 for (int level = 1; level < levelCount; level++)
1885 {
1886 redefineImage(level, getBaseLevelInternalFormat(),
1887 std::max(getBaseLevelWidth() >> level, 1),
1888 std::max(getBaseLevelHeight() >> level, 1),
1889 std::max(getBaseLevelDepth() >> level, 1));
1890 }
1891
1892 if (mTexStorage && mTexStorage->isRenderTarget())
1893 {
1894 for (int level = 1; level < levelCount; level++)
1895 {
1896 mTexStorage->generateMipmap(level);
1897
1898 mImageArray[level]->markClean();
1899 }
1900 }
1901 else
1902 {
1903 for (int level = 1; level < levelCount; level++)
1904 {
1905 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1906 }
1907 }
1908 }
1909
getBaseLevelImage() const1910 const rx::Image *Texture3D::getBaseLevelImage() const
1911 {
1912 return mImageArray[0];
1913 }
1914
getBaseLevelStorage()1915 rx::TextureStorageInterface *Texture3D::getBaseLevelStorage()
1916 {
1917 return mTexStorage;
1918 }
1919
copySubImage(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLint x,GLint y,GLsizei width,GLsizei height,Framebuffer * source)1920 void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1921 {
1922 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1923 // the current level we're copying to is defined (with appropriate format, width & height)
1924 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1925
1926 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1927 {
1928 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1929 mDirtyImages = true;
1930 }
1931 else
1932 {
1933 ensureRenderTarget();
1934
1935 if (isValidLevel(level))
1936 {
1937 updateStorageLevel(level);
1938
1939 gl::Rectangle sourceRect;
1940 sourceRect.x = x;
1941 sourceRect.width = width;
1942 sourceRect.y = y;
1943 sourceRect.height = height;
1944
1945 GLuint clientVersion = mRenderer->getCurrentClientVersion();
1946
1947 mRenderer->copyImage(source, sourceRect,
1948 gl::GetFormat(getBaseLevelInternalFormat(), clientVersion),
1949 xoffset, yoffset, zoffset, mTexStorage, level);
1950 }
1951 }
1952 }
1953
isSamplerComplete(const SamplerState & samplerState) const1954 bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
1955 {
1956 GLsizei width = getBaseLevelWidth();
1957 GLsizei height = getBaseLevelHeight();
1958 GLsizei depth = getBaseLevelDepth();
1959
1960 if (width <= 0 || height <= 0 || depth <= 0)
1961 {
1962 return false;
1963 }
1964
1965 if (!IsTextureFilteringSupported(getInternalFormat(0), mRenderer))
1966 {
1967 if (samplerState.magFilter != GL_NEAREST ||
1968 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
1969 {
1970 return false;
1971 }
1972 }
1973
1974 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
1975 {
1976 return false;
1977 }
1978
1979 return true;
1980 }
1981
isMipmapComplete() const1982 bool Texture3D::isMipmapComplete() const
1983 {
1984 int levelCount = mipLevels();
1985
1986 for (int level = 0; level < levelCount; level++)
1987 {
1988 if (!isLevelComplete(level))
1989 {
1990 return false;
1991 }
1992 }
1993
1994 return true;
1995 }
1996
isLevelComplete(int level) const1997 bool Texture3D::isLevelComplete(int level) const
1998 {
1999 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2000
2001 if (isImmutable())
2002 {
2003 return true;
2004 }
2005
2006 GLsizei width = getBaseLevelWidth();
2007 GLsizei height = getBaseLevelHeight();
2008 GLsizei depth = getBaseLevelDepth();
2009
2010 if (width <= 0 || height <= 0 || depth <= 0)
2011 {
2012 return false;
2013 }
2014
2015 if (level == 0)
2016 {
2017 return true;
2018 }
2019
2020 rx::Image *levelImage = mImageArray[level];
2021
2022 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2023 {
2024 return false;
2025 }
2026
2027 if (levelImage->getWidth() != std::max(1, width >> level))
2028 {
2029 return false;
2030 }
2031
2032 if (levelImage->getHeight() != std::max(1, height >> level))
2033 {
2034 return false;
2035 }
2036
2037 if (levelImage->getDepth() != std::max(1, depth >> level))
2038 {
2039 return false;
2040 }
2041
2042 return true;
2043 }
2044
getAttachment(GLint level,GLint layer)2045 FramebufferAttachment *Texture3D::getAttachment(GLint level, GLint layer)
2046 {
2047 FramebufferAttachment *attachment = mRenderbufferProxies.get(level, layer);
2048 if (!attachment)
2049 {
2050 attachment = new FramebufferAttachment(mRenderer, id(), new Texture3DAttachment(this, level, layer));
2051 mRenderbufferProxies.add(level, 0, attachment);
2052 }
2053
2054 return attachment;
2055 }
2056
getRenderTargetSerial(GLint level,GLint layer)2057 unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
2058 {
2059 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
2060 }
2061
isValidLevel(int level) const2062 bool Texture3D::isValidLevel(int level) const
2063 {
2064 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2065 }
2066
initializeStorage(bool renderTarget)2067 void Texture3D::initializeStorage(bool renderTarget)
2068 {
2069 // Only initialize the first time this texture is used as a render target or shader resource
2070 if (mTexStorage)
2071 {
2072 return;
2073 }
2074
2075 // do not attempt to create storage for nonexistant data
2076 if (!isLevelComplete(0))
2077 {
2078 return;
2079 }
2080
2081 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2082
2083 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2084 ASSERT(mTexStorage);
2085
2086 // flush image data to the storage
2087 updateStorage();
2088 }
2089
createCompleteStorage(bool renderTarget) const2090 rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const
2091 {
2092 GLsizei width = getBaseLevelWidth();
2093 GLsizei height = getBaseLevelHeight();
2094 GLsizei depth = getBaseLevelDepth();
2095
2096 ASSERT(width > 0 && height > 0 && depth > 0);
2097
2098 // use existing storage level count, when previously specified by TexStorage*D
2099 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2100
2101 return new rx::TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
2102 }
2103
setCompleteTexStorage(rx::TextureStorageInterface3D * newCompleteTexStorage)2104 void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
2105 {
2106 SafeDelete(mTexStorage);
2107 mTexStorage = newCompleteTexStorage;
2108 mDirtyImages = true;
2109
2110 // We do not support managed 3D storage, as that is D3D9/ES2-only
2111 ASSERT(!mTexStorage->isManaged());
2112 }
2113
updateStorage()2114 void Texture3D::updateStorage()
2115 {
2116 ASSERT(mTexStorage != NULL);
2117 GLint storageLevels = mTexStorage->getLevelCount();
2118 for (int level = 0; level < storageLevels; level++)
2119 {
2120 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2121 {
2122 updateStorageLevel(level);
2123 }
2124 }
2125 }
2126
updateStorageLevel(int level)2127 void Texture3D::updateStorageLevel(int level)
2128 {
2129 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2130 ASSERT(isLevelComplete(level));
2131
2132 if (mImageArray[level]->isDirty())
2133 {
2134 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
2135 }
2136 }
2137
ensureRenderTarget()2138 bool Texture3D::ensureRenderTarget()
2139 {
2140 initializeStorage(true);
2141
2142 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
2143 {
2144 ASSERT(mTexStorage);
2145 if (!mTexStorage->isRenderTarget())
2146 {
2147 rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
2148
2149 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
2150 {
2151 delete newRenderTargetStorage;
2152 return gl::error(GL_OUT_OF_MEMORY, false);
2153 }
2154
2155 setCompleteTexStorage(newRenderTargetStorage);
2156 }
2157 }
2158
2159 return (mTexStorage && mTexStorage->isRenderTarget());
2160 }
2161
getRenderTarget(GLint level)2162 rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
2163 {
2164 // ensure the underlying texture is created
2165 if (!ensureRenderTarget())
2166 {
2167 return NULL;
2168 }
2169
2170 updateStorageLevel(level);
2171
2172 // ensure this is NOT a depth texture
2173 if (isDepth(level))
2174 {
2175 return NULL;
2176 }
2177
2178 return mTexStorage->getRenderTarget(level);
2179 }
2180
getRenderTarget(GLint level,GLint layer)2181 rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
2182 {
2183 // ensure the underlying texture is created
2184 if (!ensureRenderTarget())
2185 {
2186 return NULL;
2187 }
2188
2189 updateStorage();
2190
2191 // ensure this is NOT a depth texture
2192 if (isDepth(level))
2193 {
2194 return NULL;
2195 }
2196
2197 return mTexStorage->getRenderTarget(level, layer);
2198 }
2199
getDepthStencil(GLint level,GLint layer)2200 rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
2201 {
2202 // ensure the underlying texture is created
2203 if (!ensureRenderTarget())
2204 {
2205 return NULL;
2206 }
2207
2208 updateStorageLevel(level);
2209
2210 // ensure this is a depth texture
2211 if (!isDepth(level))
2212 {
2213 return NULL;
2214 }
2215
2216 return mTexStorage->getRenderTarget(level, layer);
2217 }
2218
redefineImage(GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth)2219 void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2220 {
2221 // If there currently is a corresponding storage texture image, it has these parameters
2222 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2223 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2224 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2225 const GLenum storageFormat = getBaseLevelInternalFormat();
2226
2227 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
2228
2229 if (mTexStorage)
2230 {
2231 const int storageLevels = mTexStorage->getLevelCount();
2232
2233 if ((level >= storageLevels && storageLevels != 0) ||
2234 width != storageWidth ||
2235 height != storageHeight ||
2236 depth != storageDepth ||
2237 internalformat != storageFormat) // Discard mismatched storage
2238 {
2239 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2240 {
2241 mImageArray[i]->markDirty();
2242 }
2243
2244 delete mTexStorage;
2245 mTexStorage = NULL;
2246 mDirtyImages = true;
2247 }
2248 }
2249 }
2250
commitRect(GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth)2251 void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2252 {
2253 if (isValidLevel(level))
2254 {
2255 rx::Image *image = mImageArray[level];
2256 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
2257 {
2258 image->markClean();
2259 }
2260 }
2261 }
2262
Texture2DArray(rx::Renderer * renderer,GLuint id)2263 Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
2264 {
2265 mTexStorage = NULL;
2266
2267 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2268 {
2269 mLayerCounts[level] = 0;
2270 mImageArray[level] = NULL;
2271 }
2272 }
2273
~Texture2DArray()2274 Texture2DArray::~Texture2DArray()
2275 {
2276 delete mTexStorage;
2277 mTexStorage = NULL;
2278
2279 deleteImages();
2280 }
2281
deleteImages()2282 void Texture2DArray::deleteImages()
2283 {
2284 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2285 {
2286 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2287 {
2288 delete mImageArray[level][layer];
2289 }
2290 delete[] mImageArray[level];
2291 mImageArray[level] = NULL;
2292 mLayerCounts[level] = 0;
2293 }
2294 }
2295
getWidth(GLint level) const2296 GLsizei Texture2DArray::getWidth(GLint level) const
2297 {
2298 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2299 }
2300
getHeight(GLint level) const2301 GLsizei Texture2DArray::getHeight(GLint level) const
2302 {
2303 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2304 }
2305
getLayers(GLint level) const2306 GLsizei Texture2DArray::getLayers(GLint level) const
2307 {
2308 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
2309 }
2310
getInternalFormat(GLint level) const2311 GLenum Texture2DArray::getInternalFormat(GLint level) const
2312 {
2313 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2314 }
2315
getActualFormat(GLint level) const2316 GLenum Texture2DArray::getActualFormat(GLint level) const
2317 {
2318 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getActualFormat() : GL_NONE;
2319 }
2320
isCompressed(GLint level) const2321 bool Texture2DArray::isCompressed(GLint level) const
2322 {
2323 return IsFormatCompressed(getInternalFormat(level), mRenderer->getCurrentClientVersion());
2324 }
2325
isDepth(GLint level) const2326 bool Texture2DArray::isDepth(GLint level) const
2327 {
2328 return GetDepthBits(getInternalFormat(level), mRenderer->getCurrentClientVersion()) > 0;
2329 }
2330
setImage(GLint level,GLsizei width,GLsizei height,GLsizei depth,GLenum internalFormat,GLenum format,GLenum type,const PixelUnpackState & unpack,const void * pixels)2331 void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
2332 {
2333 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2334 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat, clientVersion) ? internalFormat
2335 : GetSizedInternalFormat(format, type, clientVersion);
2336 redefineImage(level, sizedInternalFormat, width, height, depth);
2337
2338 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, clientVersion, width, height, unpack.alignment);
2339
2340 for (int i = 0; i < depth; i++)
2341 {
2342 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2343 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
2344 }
2345 }
2346
setCompressedImage(GLint level,GLenum format,GLsizei width,GLsizei height,GLsizei depth,GLsizei imageSize,const void * pixels)2347 void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2348 {
2349 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2350 redefineImage(level, format, width, height, depth);
2351
2352 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2353 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
2354
2355 for (int i = 0; i < depth; i++)
2356 {
2357 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2358 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2359 }
2360 }
2361
subImage(GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,const PixelUnpackState & unpack,const void * pixels)2362 void Texture2DArray::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
2363 {
2364 GLenum internalformat = getInternalFormat(level);
2365 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2366 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, clientVersion, width, height, unpack.alignment);
2367
2368 for (int i = 0; i < depth; i++)
2369 {
2370 int layer = zoffset + i;
2371 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2372
2373 if (Texture::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, mImageArray[level][layer]))
2374 {
2375 commitRect(level, xoffset, yoffset, layer, width, height);
2376 }
2377 }
2378 }
2379
subImageCompressed(GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLsizei imageSize,const void * pixels)2380 void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2381 {
2382 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2383 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, clientVersion, width, height, 1);
2384
2385 for (int i = 0; i < depth; i++)
2386 {
2387 int layer = zoffset + i;
2388 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2389
2390 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2391 {
2392 commitRect(level, xoffset, yoffset, layer, width, height);
2393 }
2394 }
2395 }
2396
storage(GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth)2397 void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2398 {
2399 deleteImages();
2400
2401 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2402 {
2403 GLsizei levelWidth = std::max(1, width >> level);
2404 GLsizei levelHeight = std::max(1, height >> level);
2405
2406 mLayerCounts[level] = (level < levels ? depth : 0);
2407
2408 if (mLayerCounts[level] > 0)
2409 {
2410 // Create new images for this level
2411 mImageArray[level] = new rx::Image*[mLayerCounts[level]];
2412
2413 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2414 {
2415 mImageArray[level][layer] = mRenderer->createImage();
2416 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2417 levelHeight, 1, true);
2418 }
2419 }
2420 }
2421
2422 mImmutable = true;
2423 setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
2424 }
2425
generateMipmaps()2426 void Texture2DArray::generateMipmaps()
2427 {
2428 int baseWidth = getBaseLevelWidth();
2429 int baseHeight = getBaseLevelHeight();
2430 int baseDepth = getBaseLevelDepth();
2431 GLenum baseFormat = getBaseLevelInternalFormat();
2432
2433 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2434 int levelCount = mipLevels();
2435 for (int level = 1; level < levelCount; level++)
2436 {
2437 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2438 }
2439
2440 if (mTexStorage && mTexStorage->isRenderTarget())
2441 {
2442 for (int level = 1; level < levelCount; level++)
2443 {
2444 mTexStorage->generateMipmap(level);
2445
2446 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2447 {
2448 mImageArray[level][layer]->markClean();
2449 }
2450 }
2451 }
2452 else
2453 {
2454 for (int level = 1; level < levelCount; level++)
2455 {
2456 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2457 {
2458 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2459 }
2460 }
2461 }
2462 }
2463
getBaseLevelImage() const2464 const rx::Image *Texture2DArray::getBaseLevelImage() const
2465 {
2466 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2467 }
2468
getBaseLevelStorage()2469 rx::TextureStorageInterface *Texture2DArray::getBaseLevelStorage()
2470 {
2471 return mTexStorage;
2472 }
2473
copySubImage(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLint x,GLint y,GLsizei width,GLsizei height,Framebuffer * source)2474 void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2475 {
2476 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2477 // the current level we're copying to is defined (with appropriate format, width & height)
2478 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2479
2480 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2481 {
2482 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2483 mDirtyImages = true;
2484 }
2485 else
2486 {
2487 ensureRenderTarget();
2488
2489 if (isValidLevel(level))
2490 {
2491 updateStorageLevel(level);
2492
2493 GLuint clientVersion = mRenderer->getCurrentClientVersion();
2494
2495 gl::Rectangle sourceRect;
2496 sourceRect.x = x;
2497 sourceRect.width = width;
2498 sourceRect.y = y;
2499 sourceRect.height = height;
2500
2501 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0), clientVersion),
2502 xoffset, yoffset, zoffset, mTexStorage, level);
2503 }
2504 }
2505 }
2506
isSamplerComplete(const SamplerState & samplerState) const2507 bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
2508 {
2509 GLsizei width = getBaseLevelWidth();
2510 GLsizei height = getBaseLevelHeight();
2511 GLsizei depth = getLayers(0);
2512
2513 if (width <= 0 || height <= 0 || depth <= 0)
2514 {
2515 return false;
2516 }
2517
2518 if (!IsTextureFilteringSupported(getBaseLevelInternalFormat(), mRenderer))
2519 {
2520 if (samplerState.magFilter != GL_NEAREST ||
2521 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
2522 {
2523 return false;
2524 }
2525 }
2526
2527 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
2528 {
2529 return false;
2530 }
2531
2532 return true;
2533 }
2534
isMipmapComplete() const2535 bool Texture2DArray::isMipmapComplete() const
2536 {
2537 int levelCount = mipLevels();
2538
2539 for (int level = 1; level < levelCount; level++)
2540 {
2541 if (!isLevelComplete(level))
2542 {
2543 return false;
2544 }
2545 }
2546
2547 return true;
2548 }
2549
isLevelComplete(int level) const2550 bool Texture2DArray::isLevelComplete(int level) const
2551 {
2552 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2553
2554 if (isImmutable())
2555 {
2556 return true;
2557 }
2558
2559 GLsizei width = getBaseLevelWidth();
2560 GLsizei height = getBaseLevelHeight();
2561 GLsizei layers = getLayers(0);
2562
2563 if (width <= 0 || height <= 0 || layers <= 0)
2564 {
2565 return false;
2566 }
2567
2568 if (level == 0)
2569 {
2570 return true;
2571 }
2572
2573 if (getInternalFormat(level) != getInternalFormat(0))
2574 {
2575 return false;
2576 }
2577
2578 if (getWidth(level) != std::max(1, width >> level))
2579 {
2580 return false;
2581 }
2582
2583 if (getHeight(level) != std::max(1, height >> level))
2584 {
2585 return false;
2586 }
2587
2588 if (getLayers(level) != layers)
2589 {
2590 return false;
2591 }
2592
2593 return true;
2594 }
2595
getAttachment(GLint level,GLint layer)2596 FramebufferAttachment *Texture2DArray::getAttachment(GLint level, GLint layer)
2597 {
2598 FramebufferAttachment *attachment = mRenderbufferProxies.get(level, layer);
2599 if (!attachment)
2600 {
2601 attachment = new FramebufferAttachment(mRenderer, id(), new Texture2DArrayAttachment(this, level, layer));
2602 mRenderbufferProxies.add(level, 0, attachment);
2603 }
2604
2605 return attachment;
2606 }
2607
getRenderTargetSerial(GLint level,GLint layer)2608 unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
2609 {
2610 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
2611 }
2612
isValidLevel(int level) const2613 bool Texture2DArray::isValidLevel(int level) const
2614 {
2615 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2616 }
2617
initializeStorage(bool renderTarget)2618 void Texture2DArray::initializeStorage(bool renderTarget)
2619 {
2620 // Only initialize the first time this texture is used as a render target or shader resource
2621 if (mTexStorage)
2622 {
2623 return;
2624 }
2625
2626 // do not attempt to create storage for nonexistant data
2627 if (!isLevelComplete(0))
2628 {
2629 return;
2630 }
2631
2632 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2633
2634 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2635 ASSERT(mTexStorage);
2636
2637 // flush image data to the storage
2638 updateStorage();
2639 }
2640
createCompleteStorage(bool renderTarget) const2641 rx::TextureStorageInterface2DArray *Texture2DArray::createCompleteStorage(bool renderTarget) const
2642 {
2643 GLsizei width = getBaseLevelWidth();
2644 GLsizei height = getBaseLevelHeight();
2645 GLsizei depth = getLayers(0);
2646
2647 ASSERT(width > 0 && height > 0 && depth > 0);
2648
2649 // use existing storage level count, when previously specified by TexStorage*D
2650 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2651
2652 return new rx::TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
2653 }
2654
setCompleteTexStorage(rx::TextureStorageInterface2DArray * newCompleteTexStorage)2655 void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage)
2656 {
2657 SafeDelete(mTexStorage);
2658 mTexStorage = newCompleteTexStorage;
2659 mDirtyImages = true;
2660
2661 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2662 ASSERT(!mTexStorage->isManaged());
2663 }
2664
updateStorage()2665 void Texture2DArray::updateStorage()
2666 {
2667 ASSERT(mTexStorage != NULL);
2668 GLint storageLevels = mTexStorage->getLevelCount();
2669 for (int level = 0; level < storageLevels; level++)
2670 {
2671 if (isLevelComplete(level))
2672 {
2673 updateStorageLevel(level);
2674 }
2675 }
2676 }
2677
updateStorageLevel(int level)2678 void Texture2DArray::updateStorageLevel(int level)
2679 {
2680 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2681 ASSERT(isLevelComplete(level));
2682
2683 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2684 {
2685 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2686 if (mImageArray[level][layer]->isDirty())
2687 {
2688 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2689 }
2690 }
2691 }
2692
ensureRenderTarget()2693 bool Texture2DArray::ensureRenderTarget()
2694 {
2695 initializeStorage(true);
2696
2697 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2698 {
2699 ASSERT(mTexStorage);
2700 if (!mTexStorage->isRenderTarget())
2701 {
2702 rx::TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2703
2704 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
2705 {
2706 delete newRenderTargetStorage;
2707 return gl::error(GL_OUT_OF_MEMORY, false);
2708 }
2709
2710 setCompleteTexStorage(newRenderTargetStorage);
2711 }
2712 }
2713
2714 return (mTexStorage && mTexStorage->isRenderTarget());
2715 }
2716
getRenderTarget(GLint level,GLint layer)2717 rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
2718 {
2719 // ensure the underlying texture is created
2720 if (!ensureRenderTarget())
2721 {
2722 return NULL;
2723 }
2724
2725 updateStorageLevel(level);
2726
2727 // ensure this is NOT a depth texture
2728 if (isDepth(level))
2729 {
2730 return NULL;
2731 }
2732
2733 return mTexStorage->getRenderTarget(level, layer);
2734 }
2735
getDepthStencil(GLint level,GLint layer)2736 rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2737 {
2738 // ensure the underlying texture is created
2739 if (!ensureRenderTarget())
2740 {
2741 return NULL;
2742 }
2743
2744 updateStorageLevel(level);
2745
2746 // ensure this is a depth texture
2747 if (!isDepth(level))
2748 {
2749 return NULL;
2750 }
2751
2752 return mTexStorage->getRenderTarget(level, layer);
2753 }
2754
redefineImage(GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth)2755 void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2756 {
2757 // If there currently is a corresponding storage texture image, it has these parameters
2758 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2759 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2760 const int storageDepth = getLayers(0);
2761 const GLenum storageFormat = getBaseLevelInternalFormat();
2762
2763 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2764 {
2765 delete mImageArray[level][layer];
2766 }
2767 delete[] mImageArray[level];
2768 mImageArray[level] = NULL;
2769 mLayerCounts[level] = depth;
2770
2771 if (depth > 0)
2772 {
2773 mImageArray[level] = new rx::Image*[depth]();
2774
2775 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2776 {
2777 mImageArray[level][layer] = mRenderer->createImage();
2778 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2779 }
2780 }
2781
2782 if (mTexStorage)
2783 {
2784 const int storageLevels = mTexStorage->getLevelCount();
2785
2786 if ((level >= storageLevels && storageLevels != 0) ||
2787 width != storageWidth ||
2788 height != storageHeight ||
2789 depth != storageDepth ||
2790 internalformat != storageFormat) // Discard mismatched storage
2791 {
2792 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2793 {
2794 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2795 {
2796 mImageArray[level][layer]->markDirty();
2797 }
2798 }
2799
2800 delete mTexStorage;
2801 mTexStorage = NULL;
2802 mDirtyImages = true;
2803 }
2804 }
2805 }
2806
commitRect(GLint level,GLint xoffset,GLint yoffset,GLint layerTarget,GLsizei width,GLsizei height)2807 void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2808 {
2809 if (isValidLevel(level) && layerTarget < getLayers(level))
2810 {
2811 rx::Image *image = mImageArray[level][layerTarget];
2812 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2813 {
2814 image->markClean();
2815 }
2816 }
2817 }
2818
2819 }
2820