• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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